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 installThe 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 devThe 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.
// 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.
// 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:
// What `ultimabase dev` and `ultimabase start` run: the application.
export { app as default } from './src/app.ts'
Test it
npm testEach test file gets the application on a new in-memory database and a free port:
// 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
- An application's files explains each file and where new code goes.
- Models and fields adds fields and models; Relations links them.
- Access rules replaces
allow.publicwith real rules. - PostgreSQL replaces
memory()with a database that keeps its rows.