← Back to all posts
8 min readCentrali Team

Build a Full-Stack Next.js App with Centrali and Deploy to Vercel

From zero to production in minutes — scaffold a Next.js app, store data in Centrali, add webhooks and compute functions for backend logic, and deploy to Vercel or Netlify.

TutorialdeploysdkCompute

Most backend-as-a-service platforms stop at data storage. You get a database and an API, but the moment you need server-side logic — sending an email when a form is submitted, processing a payment, transforming data before it's saved — you're back to building your own backend.

Centrali is different. You get data storage, serverless compute functions, webhooks, triggers, and workflow automations — all from the same platform your frontend already talks to. No separate infrastructure. No AWS Lambda. No managing servers.

This guide walks through building a real Next.js app from scratch, deploying it to Vercel, and using Centrali for everything backend.

What You'll Build

A contact form app that:

  • Stores submissions in a Centrali collection
  • Runs a compute function on each submission (e.g., validate data, enrich it, send a notification)
  • Triggers a webhook to notify your Slack channel
  • Deploys to Vercel with zero server management

Step 1: Scaffold Your App

bash
npx @centrali-io/create-centrali-app my-app --template=nextjs cd my-app npm install

This gives you a Next.js 15 app with TypeScript, TailwindCSS, and the Centrali SDK pre-configured. Two client files are already set up:

  • src/lib/centrali.ts — a publishable key client for browser-safe operations (listing records, reading collections) and a service account client for server-side operations (creating records, calling functions)

Step 2: Set Up Your Environment

Run the env setup command:

bash
npx @centrali-io/create-centrali-app env

It detects your Next.js template, prompts for your workspace slug, publishable key, and service account credentials, then writes a .env.local file. You can also output Vercel or Netlify CLI commands directly:

bash
npx @centrali-io/create-centrali-app env --format=vercel

Where to get credentials:

  • Publishable key: Console > ACCESS > Publishable Keys > Create Key. Select which collections to expose.
  • Service account: Console > ACCESS > Service Accounts. Add it to the workspace_developers group.

Step 3: Model Your Data

In the Centrali console, create a contact-submissions collection with these properties:

PropertyType
nametext
emailtext
messagetext
statustext (default: "new")

That's your schema. No migrations, no ORM configuration, no database provisioning. The SDK discovers the schema automatically.

Step 4: Build the Form

Your scaffolded app already has a working CRUD flow. For a contact form, create a server action that writes to Centrali:

typescript
// src/app/actions.ts 'use server' import { createCentraliServerClient } from '@/lib/centrali' export async function submitContact(formData: FormData) { const centrali = createCentraliServerClient() const record = await centrali.records.create('contact-submissions', { name: formData.get('name') as string, email: formData.get('email') as string, message: formData.get('message') as string, }) return { success: true, id: record.id } }

The service account client handles authentication. The publishable key client can list submissions on the frontend. Each credential type has exactly the access it needs.

Step 5: Add Backend Logic with Compute Functions

Here's where Centrali goes beyond a typical BaaS. Instead of setting up a separate Lambda or Cloud Function, write a compute function directly in the Centrali console:

Console > COMPUTE > Functions > Create Function

javascript
// Validate and enrich contact submissions export default async function handler({ record, centrali }) { const { email, name } = record.data // Validate email if (!email || !email.includes('@')) { await centrali.records.update('contact-submissions', record.id, { status: 'invalid' }) return { status: 'rejected', reason: 'invalid email' } } // Mark as processed await centrali.records.update('contact-submissions', record.id, { status: 'processed' }) return { status: 'processed', name, email } }

Then create a trigger that fires this function whenever a record is created in the contact-submissions collection. Your function runs automatically — no cron jobs, no queue infrastructure, no deployment pipeline.

Step 6: Add a Webhook for Notifications

Want a Slack notification for every new submission? Add a webhook:

Console > COMPUTE > Webhooks > Create Webhook

  • Event: record.created
  • Collection: contact-submissions
  • URL: Your Slack incoming webhook URL

Every time a contact form is submitted, Centrali sends a POST to Slack with the record data. No code needed.

Step 7: Chain It Together with Automations

For more complex flows — like "validate the submission, then if valid, send a welcome email, then update a CRM" — use automations (workflow orchestration):

Console > COMPUTE > Automations > Create Automation

Build a multi-step workflow visually:

  1. Trigger: record.created on contact-submissions
  2. Step 1: Run validation function
  3. Step 2: If status is "processed", run email function
  4. Step 3: Call external CRM API via HTTP step

Each step can use the output of the previous step. Failed steps can retry, skip, or halt the workflow. You get a full execution log for every run.

Step 8: Deploy to Vercel

Your app is ready. Push to GitHub and deploy:

bash
git init && git add -A && git commit -m "Initial commit" gh repo create my-app --public --push

Then import in Vercel:

  1. Go to vercel.com/new
  2. Import your repository
  3. Add environment variables (the env command gave you these):
VariableValue
NEXT_PUBLIC_CENTRALI_API_URLhttps://centrali.io
NEXT_PUBLIC_CENTRALI_WORKSPACEYour workspace slug
NEXT_PUBLIC_CENTRALI_PKYour publishable key
CENTRALI_API_URLhttps://centrali.io
CENTRALI_WORKSPACEYour workspace slug
CENTRALI_CLIENT_IDYour service account ID
CENTRALI_CLIENT_SECRETYour service account secret
  1. Deploy

Your app is live. The frontend talks to Centrali via publishable key (safe for browsers). Server actions use the service account. Compute functions, triggers, webhooks, and automations all run on Centrali — zero infrastructure on your end.

Prefer Netlify?

Each scaffolded app includes a DEPLOY.md with step-by-step instructions for both Vercel and Netlify. The steps are nearly identical — just different env var commands.

What You Didn't Have to Build

  • No database server
  • No ORM or migration scripts
  • No Lambda functions or serverless framework
  • No queue system for async processing
  • No webhook infrastructure
  • No workflow engine
  • No auth server (publishable keys handle frontend, service accounts handle server-side)

Your Next.js app is a thin frontend layer. All the backend complexity — data, compute, events, workflows — lives in Centrali.

Next Steps

  • SDK Documentation — full API reference for records, collections, triggers, and more
  • Writing Functions — deep dive into compute function patterns
  • Automations — build multi-step workflows with loops and conditions
  • Search — add full-text search to your app

Building something with Centrali and want to share feedback about this feature?

Email feedback@centrali.io