Turn Any JSON File Into Your Personal Database
TL;DR: This n8n workflow transforms local JSON files into a lightweight key-value database without external dependencies. Perfect for storing config values, user preferences, or application state that needs to persist between workflow runs. No API keys, no third-party services—just your file system doing honest work.
| Difficulty | Who's This For? | Problem It Solves | Tools Used | Setup Time | Time Saved |
|---|---|---|---|---|---|
| ⭐ Level 1 | Anyone who needs persistent storage without a database | Storing values between workflow runs without external services | n8n Function nodes, Read Binary File, Move Binary Data | 10 minutes | Hours of database setup and maintenance |
David once spent an entire afternoon wrestling with Redis just to store three config values for a weekend project. By the time he got authentication working, the OAuth tokens, connection pools, and environment variables outnumbered the actual data he needed to store. I watched him curse at his terminal for twenty minutes before suggesting, "What if you just... wrote it to a file?" He gave me that look—you know the one—like I'd suggested using carrier pigeons for email delivery. But here we are.
What This Workflow Does
This workflow reads values from a JSON file on your n8n server using a key-based lookup system. Think of it as a miniature database that lives in your file system—no connection strings, no migrations, no DevOps drama. You send it a key like "user_preference" or "last_sync_timestamp," and it hands back the corresponding value from your JSON file.
The workflow accepts three inputs: the file path, the key you want to retrieve, and an optional default value if the key doesn't exist. It reads the JSON file, extracts the value for your key, and returns it in a clean format ready for the next node in your workflow. If the file doesn't exist or the key is missing, it gracefully returns your default value instead of throwing errors that wake you up at 2 AM.
This pattern shines when you're building workflows that need to remember things—like tracking which records you've already processed, storing user settings, or maintaining counters. It's persistent storage without the ceremony of a proper database, which is exactly what most automation workflows actually need.
Quick Start Guide
Before you import this workflow, you'll need to create a storage directory on your n8n server. The default location is /home/node/.n8n/local-files, but if you're running n8n in Docker, you'll find your data path in the container configuration—usually something like /data/local-files. Create the folder and set the permissions so n8n can read and write to it.
Once your storage folder exists, import the GetKey workflow from the n8n template library. You'll see five nodes connected in a chain: Manual Trigger, Config, Read Binary File, BinaryToJSON, and ReturnValue. The workflow is designed to be called by other workflows using the Execute Workflow node, not run directly—think of it as a utility function you call when needed.
To use it, create a second workflow with a Function node that outputs three properties: file (the path to your JSON file), key (the value you want to retrieve), and default (what to return if the key doesn't exist). Connect that Function node to an Execute Workflow node pointing to your GetKey workflow, and you're done. The returned data will contain your value ready to use in downstream nodes.
The Workflow Step by Step
The workflow starts with a Manual Trigger node, but don't let that fool you—this isn't meant to be triggered manually. When another workflow calls this one using the Execute Workflow node, it bypasses the trigger and feeds data directly into the next node. The Manual Trigger exists purely for testing purposes when you're debugging the workflow in isolation.
The Config node is a Function node that constructs the absolute file path for the Read Binary File node. It takes the relative file path you provide (like /4711.json) and prepends the n8n local files directory to create the full system path. This node also passes through the key and default value unchanged, making them available to later nodes in the workflow.
For Advanced Readers: The Config node uses JavaScript's template literal syntax with item.file, item.key, and item.default to access properties from the incoming data. The expression '/home/node/.n8n/local-files' + item.file concatenates the base directory with your relative path. If you're running in Docker, replace that hardcoded path with your actual data directory.
Next comes the Read Binary File node, which loads your JSON file from disk as binary data. The file path comes from the Config node's output using the expression ={{$json["file"]}}. Notice that "Always Output Data" is enabled and "Continue On Fail" is turned on—this prevents the workflow from crashing if the file doesn't exist, allowing the default value logic to kick in instead.
The BinaryToJSON node (technically called Move Binary Data) converts the raw file bytes into a JSON object that n8n can manipulate. It automatically detects that the binary data is JSON formatted and parses it into a proper JavaScript object. At this point, your entire JSON file is now accessible as structured data in the workflow.
For Advanced Readers: The BinaryToJSON node is doing character encoding detection and JSON parsing under the hood. If your file contains malformed JSON, this node will fail with a parsing error. For production workflows, you might wrap this in error handling or validation logic to catch corrupted files gracefully.
Finally, the ReturnValue node extracts the specific value you requested using a Function node. It reads the key and default value from the original Config node, then looks up that key in the parsed JSON object. If the key exists, it returns the corresponding value. If the key is missing or the file didn't exist, it returns the default value you specified.
For Advanced Readers: The expression $node["Config"].json["key"] reaches back to a previous node's output rather than using the current item. This is n8n's way of accessing data from multiple points in the workflow simultaneously. The conditional logic item[key] || defaultValue uses JavaScript's truthiness rules, which means empty strings or zero values might trigger the default—consider explicit null checking if those are valid values in your use case.
The workflow returns a clean object with a single property—your key name containing its value. This makes it trivial to use in subsequent nodes because you know exactly what property name to reference. If you requested the key "user_email," you'll get back { "user_email": "value" }, not a generic object you have to dig through.
Key Learnings
The first major concept here is the Execute Workflow pattern for creating reusable components. Instead of duplicating file-reading logic across multiple workflows, you build it once and call it like a function. This is how you maintain large n8n installations without losing your mind—shared utilities that get improvements in one place automatically flow to all consumers.
Second, notice how the workflow uses error handling implicitly rather than explicitly. The "Continue On Fail" setting combined with default value logic means errors become graceful degradation instead of workflow crashes. This is n8n philosophy in action—workflows should be resilient by design, not as an afterthought.
Third, the separation between binary data and JSON data illustrates an important n8n concept. Some nodes work with raw bytes, others with structured objects. The Move Binary Data node is your bridge between these two worlds, converting file contents into manipulable data. Understanding when to use binary versus JSON nodes prevents a lot of confusion as workflows grow complex.
What's Next
Now go build the companion WriteKey workflow (which you'll find in the n8n template library as workflow 1407). Together, these two workflows give you full read-write access to a persistent key-value store. Use it to track processing state, store user preferences, or maintain counters across workflow runs.
Then ship it to production and see what breaks. Not because it will—it won't—but because the only way to learn n8n's quirks is to deploy real workflows with real data. Start with something small, like storing the last time a workflow ran, then expand from there. By next week, you'll wonder how you ever built automation without persistent storage.
David eventually converted his Redis contraption into a simple JSON file. It took him fifteen minutes, including the time spent muttering about "overengineering." The workflow still runs today, three years later, completely unchanged. Sometimes the simplest solution really is the right one—even if it feels like cheating.
