Quickstart

Create an application, run it, query it over GraphQL and test it.

You need Node 24.7 or later: Node runs the TypeScript as it is written, with no build step.

Create the application

npm create ultimabase@latest my-app
cd my-app
npm install

The starter prints the next commands for the manager that ran it: npm, pnpm or yarn. It refuses a directory that is not empty, and a name npm cannot use for a package.

Run it

npm run dev

The application listens on http://localhost:3000, GraphQL on /graphql, and restarts when a file changes. PORT sets another port. Open http://localhost:3000/graphql in a browser for GraphiQL, or create a post and list the posts from a terminal:

curl http://localhost:3000/graphql -H 'content-type: application/json' \
  -d '{"query":"mutation { createPost(data: { title: \"Hello\" }) { id title } }"}'
curl http://localhost:3000/graphql -H 'content-type: application/json' \
  -d '{"query":"{ posts { edges { node { title } } } }"}'

The database is memory(): it starts empty at each start. npm start starts the application in production, as a host does; see Deploy.

What the starter wrote

The model: a table, its fields, and who may read and write it. Its rule, allow.public, lets anyone write, which suits a first try only: an application's rules open what its clients may do, as in Access rules.

src/models.ts
// The application's models: each one a table, its fields and who may
// read and write it.
import { allow, defineModel } from 'ultimabase'

export const Post = defineModel({
	name: 'Post',
	fields: (f) => ({
		title: f.string(),
	}),
	// Anyone may read and write posts; see `allow` for the other rules.
}).with({ access: allow.public })

The application: its database, its plugins and its models.

src/app.ts
// The application: its database, its plugins and its models.
import { graphqlPlugin } from '@ultimabase/graphql'
import { httpPlugin } from '@ultimabase/http'
import { defineApp, memory } from 'ultimabase'
import { Post } from './models.ts'

export const app = defineApp({
	// For PostgreSQL: postgres({ url: process.env['DATABASE_URL'] }) from @ultimabase/postgres.
	database: memory(),
	plugins: [
		httpPlugin(),
		graphqlPlugin(),
		// For REST too: restPlugin() from @ultimabase/rest.
	],
	models: [Post],
})

The file the dev and start scripts read, which names the application:

ultimabase.config.ts
// What `ultimabase dev` and `ultimabase start` run: the application.
export { app as default } from './src/app.ts'

Test it

npm test

Each test file gets the application on a new in-memory database and a free port:

src/app.test.ts
// Each test runs the application on a new in-memory database and a free port.
import { testApplication } from '@ultimabase/testing'
import { master } from 'ultimabase'
import { expect, it } from 'vitest'
import { app } from './app.ts'
import { Post } from './models.ts'

const running = testApplication(app)

it('lists the posts over GraphQL', async () => {
	await Post.create({ data: { title: 'Hello' } }, { as: master })
	const response = await fetch(`${running.url}/graphql`, {
		method: 'POST',
		headers: { 'content-type': 'application/json' },
		body: JSON.stringify({ query: '{ posts { edges { node { title } } } }' }),
	})
	expect(await response.json()).toEqual({
		data: { posts: { edges: [{ node: { title: 'Hello' } }] } },
	})
})

Next

On this page