So you want to run n8n without the monthly subscription fees, keep your data under your own control, and avoid the headache of server maintenance? Google Cloud Run offers exactly that sweet spot: fully managed, serverless containers with per-use pricing. This repo gives you a production-ready, modular Pulumi program that stands up the official n8n container on Cloud Run, backed by Cloud SQL Postgres, wrapped with Google Secret Manager, and ready for secure automation at scale.
- Predictable cost & scale – Pay only for requests Cloud Run serves. Autoscaling keeps latency low without paying for idle VM time.
- Data sovereignty – Your workflows, credentials, and execution history stay inside your GCP footprint, satisfying security or compliance requirements.
- Native Google integrations – Built-in OAuth consent, low-latency access to GCP services, and the ability to use Workload Identity with the deployed service account.
- Infrastructure as Code – Pulumi keeps a full inventory of the deployed resources so you can version, review, and promote changes across environments.
GCP Infrastructure costs are approximately ~$25 USD / month for a starter setup. For a simple starter setup (config that's in the repo) these are the approximate costs.
Depends on your usage and how big of a DB you need - but it's super cheap and as you scale this will be 8x cheaper than using n8n managed instance.
- ProjectServices enables the core GCP APIs (Run, Secret Manager, Cloud SQL Admin, and Resource Manager) so every other resource has the prerequisites it needs.
- ServiceAccount provisions the dedicated workload identity for n8n and grants it IAM roles for Cloud SQL and Secret Manager access.
- Database creates the Cloud SQL Postgres instance, database, user, and randomly generated password.
- Secrets stores sensitive values—database password and n8n encryption key—in Secret Manager with latest-version references for runtime.
- CloudRunService deploys the n8n container to Cloud Run, mounts the Cloud SQL proxy, injects secrets, and optionally grants public invoker access.
flowchart TD
Pulumi[Pulumi Program<br/>src/index.ts] --> Services[ProjectServices<br/>Enable APIs]
Pulumi --> SA[ServiceAccount<br/>Workload Identity]
Pulumi --> DB[Database Component<br/>Cloud SQL Postgres]
Pulumi --> Secrets[Secrets Component<br/>Secret Manager]
Pulumi --> Run[CloudRunService Component<br/>Cloud Run v2]
Services -->|Enables| Run
Services -->|Enables| Secrets
Services -->|Enables| DB
Services -->|Enables| SA
SA -->|IAM Roles| Run
SA -->|IAM Roles| DB
DB -->|Connection Name| Run
DB -->|Password| Secrets
Secrets -->|Secret Version| Run
Run -->|Optional Public Invoker| Public[(allUsers)]
- Cloud Run Service (
gcp.cloudrunv2.Service) hosts the officialdocker.io/n8nio/n8n:latestimage with CPU boost, health probes, and Cloud SQL proxy volume mount. - Cloud SQL (Postgres 15) stores workflow state, credentials, and execution logs.
- Secret Manager secures the database password and n8n encryption key generated via
@pulumi/random. - Service Account carries the minimum IAM roles (Cloud SQL Client, Secret Accessor) and is optionally granted the anonymous
roles/run.invokerbinding for public access.
- Google Cloud project with billing enabled.
- Organization policies that permit adding
allUsersto Cloud Run (only if you enable public access). - Local tooling:
gcloud,pulumiCLI, Node.js 18+ (for Pulumi Node runtime), andpnpmornpm. - Correct Google credentials in your shell (
gcloud auth application-default loginorGOOGLE_APPLICATION_CREDENTIALS).
.
├─ README.md
├─ LICENSE
├─ package.json
├─ package-lock.json # Generated when using npm
├─ pnpm-lock.yaml # Generated when using pnpm
├─ Pulumi.yaml
├─ Pulumi.self-host-n8n-gcp.yaml
├─ tsconfig.json
└─ src/
├─ config.ts # Aggregates Pulumi stack config into DeploymentConfig
├─ index.ts # Entry point orchestrating component creation
├─ components/
│ ├─ __tests__/ # Jest unit tests exercising component factories
│ │ ├─ cloudRunService.test.ts
│ │ ├─ database.test.ts
│ │ ├─ secrets.test.ts
│ │ └─ serviceAccount.test.ts
│ ├─ cloudRunService.ts # Cloud Run deployment + IAM binding
│ ├─ database.ts # Cloud SQL instance, database, user, password
│ ├─ projectServices.ts # Enables required GCP APIs
│ ├─ Secrets.ts # Secret Manager secrets for password and encryption key
│ ├─ ServiceAccount.ts # Workload identity + role attachments
│ └─ index.ts # Barrel file exporting component factories
├─ types/
│ ├─ config.types.ts # Deployment configuration interfaces
│ └─ components.types.ts # Component return types
└─ utils/
Generated directories such as node_modules/ are omitted for brevity.
## Running Tests
- `pnpm test`
The Jest suite uses Pulumi runtime mocks to validate each component in isolation. Because the mocks short-circuit calls to GCP, the tests execute quickly, cost nothing, and run safely in CI or on developer machines without needing cloud credentials. They assert on the exact resource inputs Pulumi will send to Google—catching mistakes in IAM bindings, secret wiring, or service configuration long before you reach `pulumi preview` or `pulumi up`. Keeping the specs alongside the components in `src/components/__tests__` mirrors the implementation layout, making it easy to add coverage as you evolve the infrastructure.
## Pulumi Deployment Steps
1. **Install dependencies**
```bash
pnpm install # or npm install
-
Log in to Pulumi backend (Pulumi Cloud or local)
pulumi login
-
Select or create a stack
pulumi stack init dev # or pulumi stack select <project>/<stack> -
Configure GCP project and optional overrides
pulumi config set gcp:project <your-project-id> pulumi config set gcp:region us-west2 # override default region if desired pulumi config set n8n-self-host-on-gcp:dbUser n8n # optional per-stack values pulumi config set n8n-self-host-on-gcp:allowUnauthenticated true # only if org policy allows public access
Available Pulumi config keys (namespace
n8n-self-host-on-gcp):Key Type Default Purpose dbNamestring n8nCloud SQL database name dbUserstring n8n-userDatabase username dbTierstring db-f1-microCloud SQL machine tier dbStorageSizenumber 10Storage in GB cloudRunServiceNamestring n8nCloud Run service name serviceAccountNamestring n8n-service-accountWorkload identity cloudRunCpustring 1CPU limit per container cloudRunMemorystring 2GiMemory limit per container cloudRunMaxInstancesnumber 1Cloud Run autoscaling cap cloudRunContainerPortnumber 5678n8n container port genericTimezonestring UTCDefault timezone for n8n allowUnauthenticatedboolean trueIf true, grants roles/run.invokertoallUsers -
Preview and apply
pulumi preview # review changes pulumi up # deploy resources
On success Pulumi outputs:
- Cloud Run URL (
cloudRunServiceUrl) - Cloud SQL connection name (
cloudSqlConnectionName) - Service account email (
n8nServiceAccountEmail)
- Cloud Run URL (
-
Access n8n
- If
allowUnauthenticatedistrue, open the Cloud Run URL directly. - Otherwise grant specific identities
roles/run.invoker:gcloud run services add-iam-policy-binding n8n \ --region <region> \ --project <project-id> \ --member user:<you@example.com> \ --role roles/run.invoker
- If
- Updates: Modify configuration or code, run
pulumi upto apply diffs. Pulumi handles dependency ordering and state management. - Teardown:
pulumi destroyremoves all resources—including the Cloud SQL instance—when you no longer need the stack. - Secrets rotation: Re-run
pulumi upto regenerate the database password or encryption key. Secret Manager stores new versions automatically, and the Cloud Run revision restarts with fresh credentials. - Monitoring: Use the Cloud Run Logs Viewer (link surfaced in deploy logs) and Cloud SQL monitoring dashboards for runtime health checks.
- Permission errors when enabling public access: Ensure no parent organization policy (
iam.allowedPolicyMemberDomains,run.managed.requireInvokerIam) blocksallUsers. Allow enough time for policy propagation before reapplying. - Container fails to start: Check Cloud Run logs for startup errors (commonly caused by overriding the container command or misconfigured secrets).
- Pulumi config missing: Remember both
gcp:projectandgcp:regionmust be set (or provided via environment variables) before runningpulumi up.
- Integrate n8n with Google Workspace by granting the service account scoped OAuth credentials.
- Add Cloud Logging sinks or Cloud Monitoring alerts to detect workflow failures.
- Use Pulumi deployments or CI pipelines to promote changes across dev, staging, and prod stacks.
Enjoy automation freedom with n8n on Google Cloud Run—fully controlled, cost-efficient, and managed as code.