Skip to content
New: a free website for your business, live in 48 to 72 hoursWorkflow automation on n8n and Claude, built for your businessFixed price, agreed before we start · Live in 5 to 10 business days30-day money-back guarantee on every planProfessional firms · Agencies · E-commerceYou own every workflow, in your own n8nClaude API: your data is not used for trainingHuman approval on every sensitive stepFree automation audit, no obligation
PURIST
30 days
Money-back window
14 h/wk
Modeled time saved
99.97%
Uptime SLA
< 7 days
Deploy time
PURIST AI
Claude Opus 4.7 · n8n v1.71 · <80ms
What type of business are you running? I'll show you exactly which processes we'd automate first and your estimated ROI.
Powered by n8n + Claude Opus 4.7 Get my free automation plan →
$env and Credentials in the n8n Code Node: What Works and What Doesn't
Guides 7 min read · 1,527 words

$env and Credentials in the n8n Code Node: What Works and What Doesn't

The n8n Code node can read environment variables and custom variables, but never stored credentials. What to use instead, and how to fix "access to env vars denied".

Steve, founder of PURIST

November 6, 2026

PURIST: Stuck on n8n? Our n8n experts fix and build workflows like this one, at a fixed price →

Sooner or later a Code node needs a value you do not want to hard-code: an API key, a base URL, an account ID. n8n offers several places to store such values, and the Code node can reach some of them but not others. Knowing which saves an afternoon of "is not defined" errors.

In short. Environment variables are available as $env.NAME unless the admin set N8N_BLOCK_ENV_ACCESS_IN_NODE=true, which causes "access to env vars denied". Custom variables are available as $vars.NAME. Stored credentials are never available in the Code node, by design. For authenticated API calls, use the HTTP Request node with a credential.

$env and Credentials in the n8n Code Node: What Works and What Doesn't: workflow diagram
What the Code node can read ($env, $vars) and what it never can (stored credentials). Illustration: PURIST.

What the Code node can read

SourceSyntaxAvailable in Code node
Environment variables of the instance$env.MY_VARYes, unless blocked
Custom variables (Variables feature)$vars.myVarYes
External secrets$secrets...No (expressions in credential fields only)
Stored credentialsthis.getCredentials(), $getCredentials()No, never

Environment variables with $env

On self-hosted n8n, any environment variable of the n8n process is readable:

javascript
const baseUrl = $env.CRM_BASE_URL;
return [{ json: { url: `${baseUrl}/contacts` } }];

Set the variable on the container that executes the code, then restart. With task runners in external mode, variables your scripts read must be available to the runner, so check where the Code node actually runs.

Fix "access to env vars denied"

This message means the instance has N8N_BLOCK_ENV_ACCESS_IN_NODE set to true. The documentation describes it as the switch that stops users from reading environment variables in expressions and the Code node. It defaults to false, but many hosting templates and security-conscious admins turn it on, because $env exposes every variable of the process, including database passwords.

Your options:

  • Ask the admin whether the value can move to a custom variable ($vars) instead.
  • If you are the admin and every workflow editor is trusted, set N8N_BLOCK_ENV_ACCESS_IN_NODE=false and restart. Understand the trade-off first: anyone who can edit a workflow can then print every secret of the server.
$env and Credentials in the n8n Code Node: What Works and What Doesn't: node settings
The pattern that works: code builds the request, the HTTP Request node attaches the credential. Illustration: PURIST.

Custom variables with $vars

The Variables feature stores key-value pairs at instance level, and they are readable everywhere as $vars:

javascript
const region = $vars.defaultRegion;

Variables are read-only inside workflows and visible to everyone who can use them, so they suit configuration (URLs, IDs, flags) rather than secrets. Availability depends on your n8n plan; check the Variables page of your instance.

Why credentials are never available

The n8n documentation is direct about it: Code nodes cannot access credentials, to avoid exposing authentication data. Attempts with this.getCredentials() or $getCredentials() fail with "this.getCredentials is not a function" or "$getCredentials is not defined". This is not a bug that a setting will fix.

What to do instead

  1. 1 Make the call with the HTTP Request node. Select a predefined credential (for example your HubSpot or Google credential) or a generic one such as Header Auth. The key never appears in the workflow.
  2. 2 Pick credentials dynamically. Route with a Switch node to several HTTP Request nodes, each with its own credential, or use an expression in the credential field to select one from earlier data, as the documentation suggests.
  3. 3 Let the Code node prepare the request, not send it. Build the body or query in code, then pass it to the HTTP Request node.
javascript
// Code node: build the payload only
return $input.all().map((item) => ({
  json: {
    body: { email: item.json.email, tags: ['lead', item.json.source] },
  },
}));
// Next: HTTP Request node, Body = {{ $json.body }}, credential = your API credential

What not to do

  • Do not paste API keys directly in a Code node. They end up in workflow exports, in version history and in screenshots.
  • Do not pass a secret through items to "smuggle" it into code. Execution data is stored and visible in the Executions list.
  • Do not unblock $env on a shared instance just to read one value.

Need a strong secret for a header credential? Our free secret key generator creates one in your browser.

Worked example: one workflow, three environments

You run the same workflow on a test instance and a production instance. The CRM URL and the Slack channel differ, and the API key obviously differs too. Here is a clean setup that never puts a secret in code.

On each instance, set configuration once:

  • Custom variables (Variables page): crmBaseUrl, alertChannel.
  • Or environment variables on the container: CRM_BASE_URL, ALERT_CHANNEL, if $env access is allowed.
  • A credential named the same on both instances, for example "CRM API", holding that instance's key.

Code node (prepares data only):

javascript
const base = $vars.crmBaseUrl;
return $input.all().map((item) => ({
  json: {
    url: `${base}/contacts`,
    body: { email: item.json.email, lifecycle: 'lead', source: item.json.source },
    channel: $vars.alertChannel,
  },
}));

HTTP Request node:

  • URL: {{ $json.url }}
  • Authentication: Generic Credential Type, Header Auth, credential "CRM API"
  • Body: {{ $json.body }}

When you move the workflow from test to production, nothing in it changes. The variables and the credential on each instance do the switching.

Why n8n blocks credentials in code

Credentials in n8n are encrypted at rest and only decrypted inside the nodes that use them. If Code nodes could read them, any person allowed to edit a workflow could print every key the instance holds into an execution log, which is stored and visible. Blocking it by design closes that path. The same reasoning is behind N8N_BLOCK_ENV_ACCESS_IN_NODE: environment variables often contain the database password and the encryption key.

Choosing where a value should live

ValueBest placeWhy
API key, token, passwordCredentialEncrypted, never visible in executions
Base URL, account ID, regionCustom variable ($vars)Visible, easy to change, same name across instances
Instance-level setting set by opsEnvironment variable ($env)Managed with the deployment
Business rule that changes oftenEdit Fields node or a data tableEditable without touching code

Troubleshooting table

SymptomLikely causeFix
"access to env vars denied"N8N_BLOCK_ENV_ACCESS_IN_NODE=trueUse $vars, or have the admin change it knowingly
$env.MY_VAR is undefinedVariable not set on the container that runs the codeSet it there (runner in external mode) and restart
$vars is undefined or emptyFeature not available on your plan, or variable not createdCheck the Variables page
"this.getCredentials is not a function"Trying to read credentials in codeUse the HTTP Request node with the credential
A key appears in execution dataSecret passed through itemsRemove it, rotate the key, use a credential

Common mistakes to avoid

  • Rotating a key without updating the credential. Workflows fail with 401 at the next run. Rotate, then update the credential in the same step.
  • Copying a production credential to test. Use a separate test key with limited scopes.
  • Exporting workflows with secrets in them. Exports include node parameters. With secrets in credentials, exports are safe to share.

Production checklist

  • No secret written in any Code node.
  • Authenticated calls made by HTTP Request nodes with credentials.
  • N8N_BLOCK_ENV_ACCESS_IN_NODE=true on shared instances.
  • Configuration in $vars, secrets in credentials.

Frequently asked questions

How do I access environment variables in the n8n Code node?

Use $env.VARIABLE_NAME. It works on self-hosted n8n unless N8N_BLOCK_ENV_ACCESS_IN_NODE is set to true.

What does "access to env vars denied" mean in n8n?

The instance has N8N_BLOCK_ENV_ACCESS_IN_NODE=true, so expressions and Code nodes cannot read environment variables. Use $vars or ask the admin to change the setting.

Can I get an n8n credential inside a Code node?

No. Credentials are inaccessible from the Code node by design. Use the HTTP Request node with the credential for authenticated calls.

Are $vars safe for API keys?

They are visible to everyone who can use them and shown in plain text, so treat them as configuration, not as secrets. Store secrets in credentials.

Where should I store API keys in n8n?

In credentials. They are encrypted and attached to the nodes that use them, and they do not appear in workflow exports or execution data.

Can I use $vars in expressions as well as the Code node?

Yes. Custom variables are readable as $vars.name in expressions and in the Code node.

Is it safe to set N8N_BLOCK_ENV_ACCESS_IN_NODE to false?

Only if every person who can edit workflows is trusted with every secret in the server environment, because $env can then print them.

Tags

n8ncode nodeenvironment variablescredentialssecurity
Steve, founder of PURIST

Steve founded PURIST, a workflow automation studio working with n8n, Make and Claude AI, and is the point of contact on every project. Prices and features in our articles come from vendor documentation and public pricing pages. How we research and score tools.

Complete guide

Automation Tools & Platforms

11 min read n8n Code Node: 15 JavaScript Examples You Can Copy and … 8 min read n8n Code Node With Multiple Inputs: 3 Methods That Work 7 min read Fix "Cannot find module" in the n8n Code Node (npm Pack… 7 min read n8n Code Node Errors Fixed: "Code doesn't return items … 7 min read n8n Code Node Binary Data: Read, Change and Return File… 7 min read Python in the n8n Code Node (n8n 2.x): Setup, Syntax an… 7 min read Fix n8n "The requested webhook is not registered" (Test… 6 min read n8n Webhook URL: Test vs Production, and How to Change … 7 min read n8n Respond to Webhook: Return JSON, Status Codes, Redi… 8 min read Secure an n8n Webhook: Header Auth, Basic Auth, JWT and… 7 min read n8n Webhook Not Working? 10 Causes and How to Fix Each … 7 min read n8n HTTP Request Pagination: Every Pattern With Working… 7 min read n8n HTTP Request Authentication: API Keys, Bearer Token… 7 min read n8n HTTP Request Timeout and "Aborted" Errors: Causes a… 7 min read Upload and Download Files With the n8n HTTP Request Nod… 6 min read Fix ECONNREFUSED in n8n: Docker, localhost and 127.0.0.… 6 min read n8n 429 Too Many Requests: Batching, Retries and Rate L… 6 min read Fix redirect_uri_mismatch for n8n OAuth2 Credentials (G… 7 min read n8n Expression Errors Fixed: "Referenced node is unexec… 6 min read Anatomy Claude skill: what it is, how to install it, an… 5 min read How to explain a business process with the Anatomy skil… 5 min read Anatomy vs Mermaid vs Excalidraw: which to explain a wo… 14 min read n8n LinkedIn Job Automation: Auto-Apply, Track, and Fol… 16 min read n8n HTTP Request Node: Complete Documentation and Examp… 18 min read The future of automation: how our engineering team is s… 8 min read n8n vs Make vs Zapier: the honest comparison your busin… 11 min read n8n vs Make vs Zapier: an honest comparison for product… 7 min read Webhook vs polling: the architecture decision that dete… 24 min read n8n tutorial: build your first production workflow in u… 26 min read The 9 best Zapier alternatives in 2026: an honest ranki… 21 min read Make.com tutorial: build powerful automations without c… 19 min read Automation consultant vs DIY: how to decide what is rig… 14 min read n8n Self-Hosted vs Cloud: The Complete Decision Guide (… 15 min read 5 Zapier Free Alternatives That Handle Real Production … 15 min read WhatsApp Business Automation With n8n: Build a 24/7 Cus… 17 min read Google Workspace Automation: 15 Workflows for Sheets, D… 16 min read Claude AI for Business Automation: What It Does, What I… 15 min read Airtable Automation With n8n: 10 Workflows That Make Yo… 15 min read Droven.io AI Automation Tools: Full Review and Best Alt… 14 min read Droven.io RPA and Business Automation: An Honest 2026 R… 15 min read Enterprise Workflow Automation: The Complete Guide for … 13 min read Document Workflow Automation: Software, Implementation,… 14 min read Marketing Automation Workflow: From Content Creation to… 16 min read Ad Campaign Workflow Data Model and SDR Inbound Pipelin… 14 min read ComfyUI Workflows for Business: Product Photography, Ma… 13 min read GPT-5.2 for Business Workflows and the spec-workflow-mc… 17 min read ServiceNow vs IBM BAW vs n8n: Enterprise Workflow Autom… 16 min read 9 Best Workflow Automation Tools for Small Business in …

Keep reading

More from the blog.

All articles

From audit to deployment

Experience the automation
these articles are about.

Get my free automation plan →