From 8955c8a987dcc149aa55183cd2f9c94ae4f3cc3e Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 18 Mar 2026 16:42:18 +0000 Subject: [PATCH] docs: Add .env.local.example template and dotenvx for local dev setup (no-changelog) --- .env.local.example | 59 ++++++++++++++++++++++ .gitignore | 1 + CONTRIBUTING.md | 20 ++++++++ package.json | 1 + pnpm-lock.yaml | 121 ++++++++++++++++++++++++++++++++++++++------- 5 files changed, 183 insertions(+), 19 deletions(-) create mode 100644 .env.local.example diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 000000000000..6f3f1a07e831 --- /dev/null +++ b/.env.local.example @@ -0,0 +1,59 @@ +# ============================================================================= +# n8n local development — minimal environment variables +# ============================================================================= +# This is a minimal example covering some local environment variables for development. +# Many more variables exist — search for @Env() decorators in the codebase. +# Most of them already have default values, so you only need to fill in the ones you need to change. +# +# Usage (run from the repo root): +# 1. Copy this file: cp .env.local.example .env.local +# 2. Fill in the values below +# 3. Prefix any dev command with dotenvx, for example: +# pnpm exec dotenvx run -f .env.local -- pnpm dev:be +# +# Note: dotenvx supports variable expansion (e.g. $HOME) but not shell +# tilde expansion. Use $HOME instead of ~ for paths. +# ============================================================================= + +# ----------------------------------------------------------------------------- +# Local data folder +# Source: packages/@n8n/config/src/utils/utils.ts +# ----------------------------------------------------------------------------- +N8N_USER_FOLDER= + +# ----------------------------------------------------------------------------- +# License +# Source: packages/@n8n/config/src/configs/license.config.ts +# ----------------------------------------------------------------------------- +# Tenant identifier for the license SDK (for example, self-hosted, sandbox, embed, cloud). +N8N_LICENSE_TENANT_ID= +# Activation key used to activate or upgrade the instance license. +N8N_LICENSE_ACTIVATION_KEY= +# Ephemeral license certificate. +N8N_LICENSE_CERT= + +# ----------------------------------------------------------------------------- +# AI +# Source: packages/@n8n/config/src/configs/ai.config.ts +# packages/@n8n/config/src/configs/ai-assistant.config.ts +# packages/@n8n/config/src/configs/ai-builder.config.ts +# ----------------------------------------------------------------------------- +# Whether AI features (such as AI nodes and AI assistant) are enabled globally. +N8N_AI_ENABLED= +# Base URL of the AI assistant service. +# When set, requests are sent to this URL instead of the default provider endpoint. +N8N_AI_ASSISTANT_BASE_URL= +# Whether to persist AI workflow builder sessions to the database. +N8N_AI_PERSIST_BUILDER_SESSIONS= +# API key for the Anthropic (Claude) provider used by the AI workflow builder. +# When set, enables AI-powered workflow and node building. +N8N_AI_ANTHROPIC_KEY= + +# ----------------------------------------------------------------------------- +# LangSmith tracing (optional) +# Not an n8n config var — read directly by the LangChain SDK. +# See: https://docs.smith.langchain.com/ +# ----------------------------------------------------------------------------- +LANGSMITH_ENDPOINT= +LANGSMITH_PROJECT= +LANGSMITH_TRACING= diff --git a/.gitignore b/.gitignore index e9aeb73e31d0..ece0ee4e4b8f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ yarn.lock google-generated-credentials.json _START_PACKAGE .env +.env.local .vscode/* !.claude !.vscode/extensions.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac11abf2d5fe..288e1360e28d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -187,6 +187,26 @@ To start n8n execute: pnpm start ``` +### Environment variables (optional) + +Most environment variables have default values, but if you needed to modify any a template for local environment variables is provided at `.env.local.example`. Copy it and fill in any values you need. + +```bash +cp .env.local.example .env.local +``` + +Then prefix any dev command with `dotenvx` to load it, for example: + +```bash +cd packages/cli && pnpm exec dotenvx run -f ../../.env.local -- pnpm dev + +pnpm exec dotenvx run -f .env.local -- pnpm dev:be +``` + +> **Note:** dotenvx supports variable expansion (e.g. `$HOME`) but not shell +> tilde expansion. Use `$HOME` instead of `~` for paths +> (e.g. `N8N_USER_FOLDER=$HOME/.n8n-dev`). + ## Development cycle While iterating on n8n modules code, you can run `pnpm dev`. It will then diff --git a/package.json b/package.json index a78440c24987..aa3a21de09a2 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "jest-junit": "^16.0.0", "jest-mock": "^29.6.2", "jest-mock-extended": "^3.0.4", + "@dotenvx/dotenvx": "^1.40.0", "lefthook": "^1.7.15", "license-checker": "^25.0.1", "nock": "^14.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71973283fa63..430da52c7aec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -426,6 +426,9 @@ importers: '@biomejs/biome': specifier: ^1.9.0 version: 1.9.0 + '@dotenvx/dotenvx': + specifier: ^1.40.0 + version: 1.55.1 '@n8n/eslint-config': specifier: workspace:* version: link:packages/@n8n/eslint-config @@ -525,7 +528,7 @@ importers: version: 1.0.5(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.204.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(openai@6.19.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.204.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(cheerio@1.0.0)(openai@6.19.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@langchain/community': specifier: 'catalog:' - version: 1.1.14(68cf452e30b1a32aa366c4e726b84876) + version: 1.1.14(e60a401520a07fb54545cfc8df995587) '@langchain/core': specifier: 'catalog:' version: 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.204.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(openai@6.19.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) @@ -574,7 +577,7 @@ importers: version: 3.0.1 axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 jest-mock-extended: specifier: ^3.0.4 version: 3.0.4(jest@29.7.0(@types/node@20.19.21)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.17))(@types/node@20.19.21)(typescript@5.9.2)))(typescript@5.9.2) @@ -797,7 +800,7 @@ importers: version: 4.0.7 axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 dotenv: specifier: 17.2.3 version: 17.2.3 @@ -832,7 +835,7 @@ importers: dependencies: axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 devDependencies: '@n8n/typescript-config': specifier: workspace:* @@ -1748,7 +1751,7 @@ importers: version: link:../eslint-plugin-community-nodes axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 eslint: specifier: 'catalog:' version: 9.29.0(jiti@2.6.1) @@ -2032,7 +2035,7 @@ importers: version: 1.11.0 axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 bcryptjs: specifier: 2.4.3 version: 2.4.3 @@ -2390,7 +2393,7 @@ importers: version: 10.36.0 axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 callsites: specifier: 'catalog:' version: 3.1.0 @@ -2863,7 +2866,7 @@ importers: version: link:../../../@n8n/utils axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 flatted: specifier: 'catalog:' version: 3.2.7 @@ -3184,7 +3187,7 @@ importers: version: 1.1.4 axios: specifier: 1.13.5 - version: 1.13.5(debug@4.4.3) + version: 1.13.5 bowser: specifier: 2.11.0 version: 2.11.0 @@ -5486,9 +5489,19 @@ packages: resolution: {integrity: sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ==} engines: {node: '>=18'} + '@dotenvx/dotenvx@1.55.1': + resolution: {integrity: sha512-WEuKyoe9CA7dfcFBnNbL0ndbCNcptaEYBygfFo9X1qEG+HD7xku4CYIplw6sbAHJavesZWbVBHeRSpvri0eKqw==} + hasBin: true + '@dual-bundle/import-meta-resolve@4.1.0': resolution: {integrity: sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==} + '@ecies/ciphers@0.2.5': + resolution: {integrity: sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + '@element-plus/icons-vue@2.3.1': resolution: {integrity: sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==} peerDependencies: @@ -7062,6 +7075,14 @@ packages: '@neoconfetti/react@1.0.0': resolution: {integrity: sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==} + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -12087,6 +12108,10 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + eciesjs@0.4.18: + resolution: {integrity: sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + editorconfig@1.0.4: resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} engines: {node: '>=14'} @@ -13415,6 +13440,10 @@ packages: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} @@ -15744,6 +15773,10 @@ packages: object-sizeof@2.6.5: resolution: {integrity: sha512-Mu3udRqIsKpneKjIEJ2U/s1KmEgpl+N6cEX1o+dDl2aZ+VW5piHqNgomqAk5YMsDoSkpcA8HnIKx1eqGTKzdfw==} + object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} @@ -19216,6 +19249,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + which@5.0.0: resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -22402,7 +22440,7 @@ snapshots: '@codspeed/core@4.0.1': dependencies: - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 find-up: 6.3.0 form-data: 4.0.4 node-gyp-build: 4.8.4 @@ -22519,8 +22557,24 @@ snapshots: gonzales-pe: 4.3.0 node-source-walk: 7.0.1 + '@dotenvx/dotenvx@1.55.1': + dependencies: + commander: 11.1.0 + dotenv: 17.2.3 + eciesjs: 0.4.18 + execa: 5.1.1 + fdir: 6.5.0(picomatch@4.0.3) + ignore: 5.3.2 + object-treeify: 1.1.33 + picomatch: 4.0.3 + which: 4.0.0 + '@dual-bundle/import-meta-resolve@4.1.0': {} + '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + '@element-plus/icons-vue@2.3.1(vue@3.5.26(typescript@5.9.2))': dependencies: vue: 3.5.26(typescript@5.9.2) @@ -23586,7 +23640,7 @@ snapshots: - '@opentelemetry/sdk-trace-base' - peggy - '@langchain/community@1.1.14(68cf452e30b1a32aa366c4e726b84876)': + '@langchain/community@1.1.14(e60a401520a07fb54545cfc8df995587)': dependencies: '@browserbasehq/stagehand': 1.9.0(@playwright/test@1.58.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@17.2.3)(encoding@0.1.13)(openai@6.19.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))(utf-8-validate@5.0.10)(zod@3.25.67) '@ibm-cloud/watsonx-ai': 1.1.2 @@ -23624,7 +23678,7 @@ snapshots: fast-xml-parser: 5.3.8 google-auth-library: 10.1.0 html-to-text: 9.0.5 - ignore: 5.2.4 + ignore: 5.3.2 ioredis: 5.3.2 jsdom: 23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) jsonwebtoken: 9.0.3 @@ -24063,7 +24117,7 @@ snapshots: '@azure/core-auth': 1.10.1 '@azure/msal-node': 3.8.4 '@microsoft/agents-activity': 1.2.3 - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 jsonwebtoken: 9.0.3 jwks-rsa: 3.2.2 object-path: 0.11.8 @@ -24282,6 +24336,12 @@ snapshots: '@neoconfetti/react@1.0.0': {} + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + '@noble/hashes@1.8.0': {} '@nodelib/fs.scandir@2.1.5': @@ -25418,7 +25478,7 @@ snapshots: '@rudderstack/rudder-sdk-node@3.0.0': dependencies: - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 axios-retry: 4.5.0(axios@1.13.5) component-type: 2.0.0 join-component: 1.1.0 @@ -28539,9 +28599,17 @@ snapshots: axios-retry@4.5.0(axios@1.13.5): dependencies: - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 is-retry-allowed: 2.2.0 + axios@1.13.5: + dependencies: + follow-redirects: 1.15.11(debug@4.4.1) + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axios@1.13.5(debug@4.4.3): dependencies: follow-redirects: 1.15.11(debug@4.4.3) @@ -30243,6 +30311,13 @@ snapshots: dependencies: safe-buffer: 5.2.1 + eciesjs@0.4.18: + dependencies: + '@ecies/ciphers': 0.2.5(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + editorconfig@1.0.4: dependencies: '@one-ini/wasm': 0.1.1 @@ -32076,6 +32151,8 @@ snapshots: ignore@5.2.4: {} + ignore@5.3.2: {} + ignore@7.0.5: {} imap@0.8.19: @@ -32131,7 +32208,7 @@ snapshots: infisical-node@1.3.0: dependencies: - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 dotenv: 16.6.1 tweetnacl: 1.0.3 tweetnacl-util: 0.15.1 @@ -35164,6 +35241,8 @@ snapshots: dependencies: buffer: 6.0.3 + object-treeify@1.1.33: {} + object.assign@4.1.5: dependencies: call-bind: 1.0.8 @@ -35845,7 +35924,7 @@ snapshots: posthog-node@3.2.1: dependencies: - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 rusha: 0.8.14 transitivePeerDependencies: - debug @@ -36555,7 +36634,7 @@ snapshots: retry-axios@2.6.0(axios@1.13.5): dependencies: - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 retry-request@7.0.2(encoding@0.1.13): dependencies: @@ -37173,7 +37252,7 @@ snapshots: asn1.js: 5.4.1 asn1.js-rfc2560: 5.0.1(asn1.js@5.4.1) asn1.js-rfc5280: 3.0.0 - axios: 1.13.5(debug@4.4.3) + axios: 1.13.5 big-integer: 1.6.52 bignumber.js: 9.1.2 binascii: 0.0.2 @@ -39285,6 +39364,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.1 + which@5.0.0: dependencies: isexe: 3.1.1