n8n tutorial - Lesson 04: n8n Expressions & Built-in Variables: The Complete Guide
Hi everyone, in this post we're diving deep into one of the most powerful features in n8n — expressions and built-in variables. If you've been following our n8n workflow automation tutorial series, this is the session where things really start to click. We'll walk through real hands-on examples from our T1-B8-Expressions-Playground workflow, cover the five core expression skills every n8n user needs, and flag a few tricky bugs you'll want to avoid from the start.
What Are n8n Expressions?
In n8n, an expression is a piece of dynamic code you write inside double curly braces {{ }}. Instead of typing a fixed value into a field, you write an expression that pulls live data from your workflow — like a field from the previous node, the current timestamp, or even data from a node further up the chain. This is what makes n8n workflow automation genuinely flexible rather than just mechanical.
Expressions in n8n follow JavaScript syntax, which means you can do real programming inside them — string methods, math operations, conditionals, and more. This complete n8n expressions guide will show you exactly how each piece works with real examples you can copy into your own workflows.
The Workflow We're Using
For this session, we built a workflow called T1-B8-Expressions-Playground. It runs in this order: Manual Trigger → Seed Data → Build Profile → Transform Data → Audit Report. Each node in this chain uses a different expression skill so you can see them all working together in context. Let's go through each skill one by one.
How to do:
-
Step 1 — Use $json to access current item data
The most basic expression you'll use constantly is $json. This variable gives you access to the JSON fields of the current item being processed. In the Build Profile node, for example, to pull the userId field from the incoming data, you write:
{{ $json.userId }}
Click into any field inside a Set or Edit Fields node, switch to Expression mode (click the small expression toggle next to the field), and type your expression. You'll see a live preview of the value on the right side of the editor — this is your best friend when debugging.
-
Step 2 — Apply JavaScript string methods inside expressions
Because expressions are JavaScript, you can chain any standard JS string method directly onto a value. In the Build Profile node, we used two common ones:
{{ $json.name.toUpperCase() }} — converts the name to all caps.
{{ $json.name.charAt(0) }} — pulls just the first character, useful for initials or avatar labels.One important note: you cannot get these methods by dragging and dropping a field from the data panel. Drag-drop only inserts the plain field reference like {{ $json.name }}. To use methods like .toUpperCase() or .charAt(), you have to type them manually. This is a key distinction in the n8n editor that trips up a lot of beginners.
-
Step 3 — Do math and use Number() to avoid type bugs
In the Transform Data node, we tried adding two fields together — something like age plus a bonus value. The first attempt used:
{{ $json.age + 10 }}
The result was 3010 instead of 40. This happens because n8n sometimes carries field values as strings, and in JavaScript the + operator on strings means concatenation, not addition. So "30" + 10 gives you "3010".
The fix is simple — wrap your variable in Number() to force it to be treated as a number:
{{ Number($json.age) + 10 }}
This is one of the most common bugs in any n8n tutorial on expressions, so write it in your notes now. Whenever you do arithmetic in an expression and the result looks wrong, check whether your values are actually numbers or strings.
-
Step 4 — Build strings with template literals (backtick syntax)
Template literals let you mix fixed text and dynamic variables cleanly in one expression. Instead of trying to concatenate strings with +, you use backticks and insert variables with ${ } inside them. In the Build Profile node we built a description field like this:
{{ `Hello, my name is ${$json.name} and I am ${$json.age} years old.` }}
The whole expression goes inside the outer {{ }}, and the backtick template lives inside that. This pattern is also exactly what we used in the Build Description Code node in our Switch workflow — combining team, id, title, and status into one formatted string. Template literals make your output readable and easy to maintain.
-
Step 5 — Reference data from a different node using $node
Sometimes you need data from a node that isn't the one directly before your current node. For example, in the Audit Report node, we needed to pull data from the Seed Data node, which was several steps back in the chain. The built-in variable for this is $node:
{{ $node["Seed Data"].json.fieldName }}
Use the exact node name in quotes inside the square brackets — this is case-sensitive. If your node is named Seed Data with a capital S and D, write it exactly that way. This variable is incredibly useful in complex workflows where data branches and merges and you need to reach back to an earlier step.
-
Step 6 — Use $now for timestamps and date formatting
n8n has a built-in variable called $now that gives you the current date and time. You used it in the T1-B7-Schedule-Demo workflow to add a timestamp field with {{ $now }}. In the expressions playground, we went further and formatted the output using the .toFormat() method:
{{ $now.toFormat('yyyy-MM-dd HH:mm:ss') }}
The timezone n8n uses locally was confirmed as Asia/Ho_Chi_Minh (UTC+07:00) — this matters if your workflow relies on time comparisons or scheduling. If you're on a cloud instance, check your instance timezone setting in the n8n settings panel because it may default to UTC.
-
Step 7 — Use $workflow to access workflow metadata
The $workflow variable gives you metadata about the workflow itself — things like its name and ID. In the Audit Report node, we used it to stamp the report with the workflow name:
{{ $workflow.name }}
You can also access {{ $workflow.id }} and {{ $workflow.active }} which returns true or false depending on whether the workflow is currently published and active. This is handy when you're building logging or monitoring workflows that need to identify which workflow they belong to.
-
Step 8 — Understand drag-drop vs manual typing
In the n8n expression editor, you can drag a field from the data preview panel on the left and drop it into a field. This inserts a basic reference like {{ $json.fieldName }} automatically. That's great for simple lookups.
But the moment you want to do anything more — add a method, format a string, do math, or reference another node — you have to type it manually. Drag-drop gives you the raw reference only. Think of drag-drop as a shortcut for simple cases and manual typing as the full tool. Once you get comfortable typing expressions, you'll find you use drag-drop less and less.
-
Step 9 — Watch out for the "Include Other Input Fields" bug in Set nodes
This one bit us during the Switch workflow and it directly affects expressions. In the Label Marketing, Label Sales, and Label Engineering Set nodes, the Include Other Input Fields option was set to Selected with only the userId field ticked. This silently dropped all other fields — id, title, and completed — from the output.
When the Build Description Code node downstream tried to reference $input.item.json.id and $input.item.json.title, they came back as undefined because those fields no longer existed in the data.
The fix: go back to each Set node, find the Include Other Input Fields setting, and change it from Selected to All. This ensures all fields flow through the node, not just the ones you explicitly ticked. Any time your expressions are returning undefined, check what the upstream nodes are passing through — this setting is one of the most common culprits.
-
Step 10 — Quick reference: the five built-in variables you'll use most
To wrap up the practical skills, here's a clean summary of the five variables from this session that you'll use in almost every real workflow:
$json — Current item's data fields. Example: {{ $json.email }}
$node["NodeName"].json.field — Data from a specific upstream node. Example: {{ $node["Seed Data"].json.id }}
$now — Current timestamp. Example: {{ $now.toFormat('yyyy-MM-dd') }}
$workflow.name — The workflow's name. Example: {{ $workflow.name }}
Number() — Force a value to be numeric before doing math. Example: {{ Number($json.score) + 5 }}Keep this list somewhere accessible. In any n8n tutorial situation — whether you're following along here or troubleshooting your own flows — these five will cover the majority of what you need.
Bonus: Versioning and the Publish Button
One thing that came up during the Schedule Trigger session (Step 7 of this series) that's worth mentioning alongside expressions: when you click Publish in n8n, it creates a snapshot of your workflow. Automated runs use the published snapshot. Manual runs from the editor use your current unsaved version. This means you can safely experiment with expressions in the editor without breaking your live production workflow. The Publish button turns green when the editor matches the published version, and yellow when you have unpublished changes.
Conclusion:
n8n expressions are what separate a basic automation from a truly smart workflow — they let your nodes talk to each other, handle real data dynamically, and react to context instead of just running fixed logic. With the five skills covered in this n8n expressions guide — $json, JavaScript methods, Number() for math, template literals, and $node for cross-node data — you have everything you need to build professional-grade workflows as part of your ongoing n8n workflow automation journey.
If you have any questions, feel free to leave a comment below. Thank you!
Tags: n8n expressions guide, n8n tutorial, n8n workflow automation, n8n built-in variables, n8n beginners guide, n8n expressions examples, workflow automation tutorial, n8n $json $now $workflow
Good job!
ReplyDeleteThank you!
DeleteThank you so much for the encouragement – it really means a lot! We're thrilled you enjoyed the content and look forward to sharing more with you soon.
DeleteCould you explain detail for Use $json to access current item data?
ReplyDelete"# Reply
DeleteAbsolutely! The `$json` variable gives you direct access to all the data from your current item, so you can reference any field using dot notation like `$json.fieldName` to pull specific values into your workflow. I'd be happy to walk you through a practical example if you share what data you're trying to access!"
I don't like this post.
ReplyDeleteThank you for taking the time to share your feedback with us! We'd love to hear what specifically didn't work for you so we can improve future posts.
ReplyDeleteOk. Thank you for your reply. I will read detail on your blog to review.
ReplyDelete