"Hello World" Examples Node.js Nest.js

Nest.js showcase

NestJS showcase exercising the full managed-service set on Zerops — PostgreSQL, Valkey cache, NATS broker, object storage, and Meilisearch — wired across a NestJS API, a static SPA frontend, and a standalone background worker, with all the essentials a porter needs to clone, deploy, and adapt the stack to their own product.

Lightweight project core
Single dedicated container with balancers (L3/L7), logger and statistics services
api:3000
Node.js

Containers

1Shared Core

0.5 GBRAM

GBDisk (SSD)

 GitHub repo
app
Static

Containers

1Shared Core

0.5 GBRAM

GBDisk (SSD)

 GitHub repo
worker
Node.js

Containers

1Shared Core

0.5 GBRAM

GBDisk (SSD)

 GitHub repo
db:5432,:6432
PostgreSQL

Container

1Shared Core

0.25 GBRAM

GBDisk (SSD)

cache:6379,:6380
Valkey

Container

1Shared Core

0.25 GBRAM

GBDisk (SSD)

broker:4222,:8222
NATS

Container

1Shared Core

0.25 GBRAM

GBDisk (SSD)

storage
Object storage

External

GBSize

search:7700
Meilisearch

Container

1Shared Core

0.25 GBRAM

GBDisk (SSD)

10Shared Cores

GBRAM

10 GBDisk (SSD)

GBObject storage

$19.1

Per month for
Resources cost
add
FreePer month for
Lightweight pkg.

After deploying one of the environments and getting to know Zerops, you have two paths forward. 1 Clone our GitHub repositories and use the whole recipe as a template, or if you already have an existing application on a similar stack, 2 integrate the recipe setup with your application.

or
Taking ownership of theenvironment

Small production environment offers a production-ready setup optimized for moderate throughput — two runtime containers per codebase on shared CPU keep rolling deploys zero-downtime, managed services stay single-instance with snapshot backups.

📦Clone the template repositories1Find your service name2Configure deployment pipeline3Deploy to production4Configure autoscaling5Set up your domain🎉You are good to go!6Set up log forwarding (Optional)7Configure database backups (Optional)8Set up diagnostic access (Optional)🏁What's next?

Taking ownership of the Small Production environment

📦 Clone the template repositories

Fork or clone the following to your local machine or GitHub account:

1. Find your service name

Many commands and configurations need the exact name of your service. You can find it in the Zerops Dashboard.

  • Open your project in the Zerops Dashboard.
  • In the project overview, find the service you want to manage.
  • Use this exact name whenever a command or pipeline configuration asks for <service-name>.
Zerops GUI: Locating the Service Name

2. Configure deployment pipeline

Go to Service Settings > Pipelines & CI/CD Settings in the Zerops Dashboard and connect your repository.

For production, use a trigger on new tags. This keeps deployments intentional and tied to a specific version. You can also add a regex filter, such as ^v[0-9]+\.[0-9]+\.[0-9]+$, if you want to allow only semantic version tags.

Zerops GUI: Triggers

Alternatively, add zcli push to your existing CI/CD pipeline if you want full control over when deployments happen.

Learn more about pipeline triggers: https://docs.zerops.io/features/pipeline

3. Deploy to production

Create and push a new Git tag to deploy a specific version of your app:

bash
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0

lightbulb Tip

Open the pipeline detail in the Zerops Dashboard to check the build progress and verify that all steps finish successfully.

4. Configure autoscaling

Review the autoscaling settings for your runtime services and databases in Service Settings > Automatic Scaling Configuration in the Zerops Dashboard.

Zerops GUI: Autoscaling configuration

The most important settings are:

yaml
verticalAutoscaling:
  minRam: 1
  minFreeRamGB: 0.5
  minFreeRamPercent: 20

report Caution

Pay attention to minFreeRamGB. This value tells Zerops when to scale RAM vertically. Adjust it based on your app’s real memory needs. RAM scales up immediately, while CPU scales after two consecutive measurements below the threshold.

[!TIP] Run a quick stress test with a tool like hey before real users arrive. This helps you see how your app behaves under load and tune the autoscaling settings.

5. Set up your domain

To send real traffic to your app, configure public HTTP access in Service Settings > Public Access & Internal Ports in the Zerops Dashboard.

Add your custom domain and point your DNS records to the Zerops IPs shown in the dashboard:

Zerops GUI: Public access and custom domain
text
Type   Name          Content          TTL
A      example.com   <zerops-ipv4>    Auto
AAAA   example.com   <project-ipv6>   Auto

For wildcard domains, add a CNAME record for SSL validation.

Check the public access documentation: https://docs.zerops.io/features/access

lightbulb Tip

When changing DNS records for production, start with a low TTL value. Make sure SSL certificates are active before you disable the fallback Zerops subdomain.

Once everything works, you can disable the Zerops subdomain so all traffic goes through your custom domain.


🎉 You are good to go!

Your application is live in production and the core setup is complete.

The following sections are optional. They cover extra production features such as log forwarding, backups, and diagnostic access. You can stop here and come back later when you need them.


6. Set up log forwarding (Optional)

To send logs to an external service, go to Project Settings > Log Forwarding & Logs Overview in the Zerops Dashboard.

You can forward logs to services like Better Stack, Papertrail, or your own self-hosted solution.

Learn more about log forwarding: https://docs.zerops.io/references/logging

7. Configure database backups (Optional)

Manage automated encrypted backups in Service Settings > Backups in the Zerops Dashboard.

By default, backups run daily between 00:00 and 01:00 UTC.

Before a major deployment, create a manual protected backup:

bash
zcli backup create <db-service> --tags pre-deploy,protected

Read the backup documentation for more options: https://docs.zerops.io/features/backup

8. Set up diagnostic access (Optional)

Use zCLI and VPN access when you need to inspect or maintain services directly.

For runtime services:

bash
zcli vpn up
ssh <service-name>.zerops

For databases, connect through the VPN to reach the project’s private network, or set up secure direct IP access for your database admin tools.

Check the VPN documentation: https://docs.zerops.io/references/cli/commands#vpn-up

🏁 What's next?

See how the applications were integrated with Zerops

Even when you use this recipe as a template, it's good to have an idea of what steps were taken to best integrate the apps into Zerops.

Deploy environments for the rest of the development lifecycle

One environment rarely tells the full story — deploy environments for other stages of development to see how they work on Zerops.

Knowledge Base

Node.jsapi

zerops-recipe-apps/nestjs-showcase-api

Object-storage runs on a MinIO backend

The data plane (PutObject, GetObject, ListObjectsV2, multipart uploads, pre-signed URLs) is S3-compatible end-to-end. Control-plane and AWS-only features aren't on the managed backend: no archival tiers (Glacier, Deep Archive), no Object Lock / WORM, no lifecycle rules, no S3 Select or Inventory, no Transfer Acceleration, no CloudFront integration. Adapting this recipe to a product that needs any of those means planning a separate AWS S3 tier alongside; the rest of the recipe stays intact.

Staticapp

zerops-recipe-apps/nestjs-showcase-app

${API_URL} resolves at project create, not on subdomain rotation

The project-scope API_URL / FRONTEND_URL constants compose from ${zeropsSubdomainHost} once at provision time and don't auto-track if you later swap apistage for a custom domain. The SPA bakes VITE_API_URL: ${API_URL} at build time, so swapping the api origin means updating API_URL in the Zerops UI's project envs AND redeploying prod so a fresh build picks up the new value. Dev is exempt — Vite is long-lived, so a VITE_API_URL change plus a Vite restart is enough.

base: static is Nginx — no Node at request time

The app ships a compiled Vite bundle to an Nginx-backed runtime: ~2 MB RAM per replica, SPA fallback built in. Anything that needs request-time code — server-rendered routes (Next.js / Nuxt server components), dynamic redirects, edge functions, BFF endpoints — requires switching to base: nodejs@22 with an explicit start: and the runtime cost balloons to ~80 MB per replica. If your product is hybrid SSR/SPA, plan the runtime model up front rather than as an afterthought.

Node.jsworker

zerops-recipe-apps/nestjs-showcase-worker

Meilisearch is single-node across every tier

The recipe ships mode: NON_HA for the search service on every tier, including HA Production — Zerops's managed Meilisearch is single-node with vertical autoscaling. Production scaling is bounded by the per-instance heap; horizontal sharding isn't a one-yaml-edit upgrade. If your index will grow past ~10M documents or query QPS spikes past single-node throughput, plan a vertical bump (verticalAutoscaling.minRam in zerops.yaml) before the ceiling, or budget for an external search service.

Each DDL-owning codebase needs its own execOnce migrator key

The recipe scopes api and worker migrations under separate ${appVersionId}-api-migrate and ${appVersionId}-worker-migrate execOnce keys so they don't contend on a shared lock. If you add a third codebase that issues DDL on the same database, give it its own role-suffixed key (${appVersionId}-<codebase>-migrate) — sharing the api or worker key burns the per-deploy gate for whichever migrator loses the race.