# Deploy Your First App You've got a live app running on Zerops. Now let's make it actually yours. This page walks you through deploying the feedback app we showed you at the top of the quickstart - a Node.js app with a PostgreSQL database, auto-deploy on every git push, and a wall of everyone who's made it through. If you'd rather skip straight to your own code, there's a note at the bottom for that. ### Deploy the feedback app Start from the recipe template. Click the link below, pick a name for your repo, and hit **Create repository**: **[github.com/new?template_name=recipe-nodejs&template_owner=zeropsio](https://github.com/new?template_name=recipe-nodejs&template_owner=zeropsio)** Then clone your new repo and install dependencies: ```bash git clone https://github.com/your-username/your-repo.git cd your-repo npm install ``` The repo uses TypeScript. You only need to touch two files: `src/app.ts` and `src/db.ts`. Leave `src/index.ts` and `src/config.ts` exactly as they are. **Replace `src/db.ts`** with this: ```ts export const connectDB = async () => { const client = new Client({ host: config.db.host, port: config.db.port, user: config.db.username, password: config.db.password, database: config.db.database, }); await client.connect(); await client.query(` CREATE TABLE IF NOT EXISTS clicks ( id SERIAL PRIMARY KEY, seed INTEGER NOT NULL, clicked_at TIMESTAMPTZ DEFAULT NOW() ) `); return client; }; ``` **Replace `src/app.ts`** with this: ```ts const app = express(); app.use(express.static(path.join(__dirname, '../public'))); app.get('/count', async (_, res) => { const client = await connectDB(); const result = await client.query( 'SELECT seed FROM clicks ORDER BY id ASC LIMIT 20' ); const countResult = await client.query('SELECT COUNT(*) FROM clicks'); await client.end(); res.json({ count: parseInt(countResult.rows[0].count), seeds: result.rows.map((r) => r.seed), }); }); app.post('/click', async (_, res) => { const client = await connectDB(); const seed = Math.floor(Math.random() * 1000000); await client.query('INSERT INTO clicks (seed) VALUES ($1)', [seed]); const countResult = await client.query('SELECT COUNT(*) FROM clicks'); await client.end(); res.json({ count: parseInt(countResult.rows[0].count), seed }); }); app.get('/status', (_, res) => { res.status(200).send({ status: 'UP' }); }); export default app; ``` **Create a `public/` folder** at the repo root and add `public/index.html`:
```html Zerops Quickstart

You made it. 🎉

You just deployed a real app: managed database, private network, auto-deploy. Let us know you made it through.

...

Node.js 20 PostgreSQL 16 Zerops
```
The `zerops.yml` already exists in the repo. Update `deployFiles` to include the `public` folder: ```yaml zerops: - setup: app build: base: nodejs@20 prepareCommands: - npm install -g typescript buildCommands: - npm i - npm run build deployFiles: - ./dist - ./node_modules - ./public - ./package.json run: base: nodejs@20 ports: - port: 3000 httpSupport: true envVariables: NODE_ENV: production DB_NAME: db DB_HOST: DB_USER: DB_PASSWORD: # or use the full connection string: # DB_CONNECTION_STRING: start: npm run start:prod healthCheck: httpGet: port: 3000 path: /status ``` :::tip How Zerops env variables work Zerops automatically generates credentials for every managed service. The variable names are derived from the service hostname — so if your database service is named `db`, the variables are ``, ``, ``, and ``. If you named it `postgres` instead, they'd be ``, ``, and so on. ::: Push to your repo and connect GitHub in the next section. ```bash git add . git commit -m "add feedback app" git push ``` :::note Want to build something else instead? Skip the feedback app. Pick the recipe matching your stack from [app.zerops.io/recipes](https://app.zerops.io/recipes), add a `zerops.yaml` to your repo root copying the structure from the recipe, and adjust `buildCommands`, `deployFiles`, and `start` for your stack. The database env variables (``, ``, ``) stay the same regardless of what you're building. ::: ### Connect GitHub and auto-deploy 1. Click into your **app** service 2. Scroll down to **Pipelines & CI/CD settings** 3. Click **GitHub** to connect your repo 4. Select your repo and set **Trigger on** to **Push to Branch**, pick `main` 5. In the **"Which `setup` from zerops.yml to use"** field, type `app` 6. Click **Activate pipeline trigger** That's it. Every push to main now builds and deploys automatically. Zero downtime, Zerops runs the new version alongside the old one, waits for a health check, then switches traffic over. You can also trigger deploys manually with the Zerops CLI: `zcli push`. ### Add yourself to the list Deployed the feedback app? Open your live app URL and click **"I followed the Zerops quickstart"**. You'll show up alongside everyone else who's made it through. Check out everyone who's already made it: [app-25be-3000.prg1.zerops.app](https://app-25be-3000.prg1.zerops.app/) ### If something breaks Got a 502 or an app crash on startup? Start here. **Check the runtime logs first.** Dashboard, click your app service, click the three-dot menu, then **Runtime log**. The error will be there, usually in the last few lines. Two things come up most often on a first deploy: :::tip Debug locally with VPN Install zcli first (see [CLI reference](/references/cli)), then run `zcli vpn up [your-project-id]` and your machine joins the project's private network. You can connect to `db:5432` directly from your local machine using TablePlus, psql, or any database client. You can disable SSL when connecting over VPN - the tunnel itself handles security either way. If `db` doesn't resolve, try `db.zerops` instead. ::: ### What's next - **[SSH into your container](/references/networking/ssh)**: `zcli service shell [service-name]` for full Linux access - **[Custom domain](/references/networking/public-access)**: add your domain, SSL is automatic - **[Autoscaling](/features/scaling)**: set min and max CPU and RAM, Zerops scales within that range automatically - **[Add more services](/features/infrastructure)**: queues, search engines, object storage, just add them to your project - **[Try ZCP](/zcp/quickstart)**: Zerops' AI agent that can deploy, debug, and operate your project :::note Stuck? Jump into the [Zerops Discord](https://docs.zerops.io/discord). The community is active and the team is there. :::