---
title: "6: SurrealKit and the first table | SurrealDB University"
description: "Initialise a SurrealKit project, define a project table, and apply schema with sync."
url: https://surrealdb.com/learn/schemas/page-06
---

![Course content preview](https://surrealdb.com/assets/static/course-schemas.D4CFbBhP.avif)

[Back to Courses](https://surrealdb.com/learn)

Course chapters

[Schema internals and migrations](https://surrealdb.com/learn/schemas) Internals [1: Schemaless vs. schemafull](https://surrealdb.com/learn/schemas/page-01) [2: Schema internals](https://surrealdb.com/learn/schemas/page-02) [3: Migrations](https://surrealdb.com/learn/schemas/page-03) [4: Data types](https://surrealdb.com/learn/schemas/page-04) [5: Automation](https://surrealdb.com/learn/schemas/page-05) Migrations [6: SurrealKit and the first table](https://surrealdb.com/learn/schemas/page-06) [7: Activities and seed data](https://surrealdb.com/learn/schemas/page-07) [8: Computed and asserted fields](https://surrealdb.com/learn/schemas/page-08) [9: Graph dependencies](https://surrealdb.com/learn/schemas/page-09) [10: Sync vs rollouts](https://surrealdb.com/learn/schemas/page-10) [11: Milestones](https://surrealdb.com/learn/schemas/page-11) [12: People and indexes](https://surrealdb.com/learn/schemas/page-12) [13: Events and CI](https://surrealdb.com/learn/schemas/page-13) [14: Capstone](https://surrealdb.com/learn/schemas/page-14)

# 6: SurrealKit and the first table

The previous sections treated schema as SurrealQL you typed by hand. From here we will write the same `DEFINE` statements into files and let [SurrealKit](https://surrealdb.com/docs/manage/schema-migration) apply them for you. The example running through the rest of this course is a project planning app, the same shape as the [project planning sample](https://surrealdb.com/docs/learn/schema-management/schema-design/sample-industry-schemas#project-planning) in the schema design docs. We'll start small, then add graph relations, `COMPUTED` fields, indexes, and `DEFINE EVENT` as the chapters go on.

## Initialise the repository

In an empty app repository (or your course `practice/` folder), run:

```bash
surrealkit init --minimal
```

`--minimal` scaffolds the base SurrealKit layout without any of the optional template features (Organizations, Teams, and so on). That empty `database/schema/` folder is what the rest of this course builds on.

You should see something like:

```text
Using template: SurrealKit starter
  Optional building blocks for a new SurrealDB project

Scaffolded project in ./database

  surrealkit.toml
  ./database/
  ├── schema/
  ├── rollouts/
  ├── snapshots/
  ├── tests/
  │   ├── suites/
  │   └── fixtures/
  ├── seed/
  │   └── seed.surql
  └── setup.surql

No features selected — scaffolded a bare project.
```

Here is what has been created by the command, and why:

| Path | Role |
| --- | --- |
| `surrealkit.toml` | Project config (including optional template variables) |
| `database/schema/` | Your `DEFINE` statements (desired catalog state); starts empty, you add files next |
| `database/seed/` | Optional fixture data (init drops a stub `seed.surql`; replace or delete it before seeds used in part [7](https://surrealdb.com/learn/schemas/page-07)) |
| `database/tests/` | `surrealkit test` suites under `tests/suites/` plus fixtures. The printed tree elides two files that init does write: `tests/config.toml` (actors and timeouts) and a starter `tests/suites/smoke.toml`, both used in part [13](https://surrealdb.com/learn/schemas/page-13) |
| `database/rollouts/` | Generated rollout manifests |
| `database/snapshots/` | Schema/catalog snapshots for rollout planning |
| `database/setup.surql` | SurrealKit’s own metadata tables (see below) |

Note

Plain `surrealkit init` (without `--minimal`) shows a feature checklist. Selecting items copies ready-made org/permission schema, seeds, and tests into `database/`. That's handy for a real app starter, but a distraction here. If you already ran the interactive init and enabled features, delete `database/` and re-run `surrealkit init --minimal`, or remove the extra feature files by hand. See [Templates](https://github.com/surrealdb/surrealkit#templates) in the SurrealKit README for `--feature`, `-y`, and custom `--from` templates.

## Start SurrealDB and sync

It's now time to start our database with a single root user.

```bash
surreal start --user root --pass secret
```

Next, create `database/schema/project.surql` with a few definitions for the `project` table:

```surql
DEFINE TABLE project SCHEMAFULL;
DEFINE FIELD name ON project TYPE string ASSERT $value.len() > 0;
DEFINE FIELD description ON project TYPE option<string>;
DEFINE FIELD created_at ON project TYPE datetime DEFAULT time::now();
```

This is deliberately small, holding one `SCHEMAFULL` table, a required name, an optional description, and a `DEFAULT` timestamp from part [5](https://surrealdb.com/learn/schemas/page-05).

With that file present, we are now ready to sync the schema.

The `sync` command is for local and other disposable databases. These are instances you're happy to wipe or reshape freely, such as a local `memory` database, a throwaway data directory, a CI ephemeral DB. Sync makes the live catalog match your files immediately, including `REMOVE` for definitions you deleted from those files. Parts [10](https://surrealdb.com/learn/schemas/page-10)–[14](https://surrealdb.com/learn/schemas/page-14) cover `rollouts` for shared staging and production, where destructive steps wait for an explicit `complete` phase. Don't point everyday `sync` at a database you share with other people or services.

In another terminal, from the project root, apply the schema:

```bash
surrealkit sync --user root --pass secret --ns main --db main
```

You should see a message like this:

```text
applied database/schema/project.surql
```

SurrealKit reads every file under `database/schema/` and runs the `DEFINE` statements against your namespace and database. Check that the table came through with a one-shot query (or run the same SurrealQL in SurrealDB Studio):

Bash

PowerShell

```bash
echo 'INFO FOR TABLE project;' | surreal sql --user root --pass secret --ns main --db main --pretty --hide-welcome
```

You should see the three field definitions for this schemafull table.

## What SurrealKit added beside `project`

Note that `database/setup.surql` isn't product schema. Sync applies it so SurrealKit can keep track of its own work. After your first successful sync, list the tables:

Bash

PowerShell

```bash
echo '(INFO FOR DB).tables;' | surreal sql --user root --pass secret --ns main --db main --pretty --hide-welcome
```

```surql
{
	__entity: 'DEFINE TABLE __entity TYPE NORMAL SCHEMAFULL PERMISSIONS NONE',
	__rollout: 'DEFINE TABLE __rollout TYPE NORMAL SCHEMAFULL PERMISSIONS NONE',
	__seed: 'DEFINE TABLE __seed TYPE NORMAL SCHEMAFULL PERMISSIONS NONE',
	project: 'DEFINE TABLE project TYPE NORMAL SCHEMAFULL PERMISSIONS NONE'
}
```

| Table | Role after this chapter |
| --- | --- |
| `project` | Your application table |
| `__entity` | Bookkeeping: file hashes, per-definition tracking, sync metadata |
| `__rollout` | Rollout run state; empty until you use rollouts in part [10](https://surrealdb.com/learn/schemas/page-10) |
| `__seed` | Seed-file hashes; empty until you run `surrealkit seed` in part [7](https://surrealdb.com/learn/schemas/page-07) |

All three `__`-prefixed tables come from `database/setup.surql`, so they exist from the first sync onwards even though only `__entity` has anything in it yet.

Take a look at the metadata SurrealKit just wrote:

Bash

PowerShell

```bash
echo 'SELECT * FROM __entity; SELECT * FROM __rollout;' | surreal sql --user root --pass secret --ns main --db main --pretty --hide-welcome
```

`__rollout` should come back empty for now. `__entity` is where the interesting data lives at this point:

| Field | Meaning |
| --- | --- |
| `id` | SurrealDB record id for this metadata record |
| `ns` | Which kind of bookkeeping this is (`sync`, `schema`, or `meta`) |
| `key` | Identity inside that namespace |
| `val` | Payload (hash, paths, state, …) |
| `updated_at` | When SurrealKit last wrote the record |

### `ns: 'sync'`: file-level hashes

Example (your hashes will differ):

```surql
{
	ns: 'sync',
	key: 'database/schema/project.surql',
	val: { hash: '15966cde…aa3a' },
}
```

| Piece | Meaning |
| --- | --- |
| `key` | Path of the schema file SurrealKit applied |
| `val.hash` | SHA-256 of that file’s contents |

On the next sync, SurrealKit re-hashes each file on disk. If the hash still matches this record, it skips re-running that file’s `DEFINE` statements.

### `ns: 'schema'`: one record per managed definition

Examples:

```surql
{ ns: 'schema', key: 'table::project', val: { … } }
{ ns: 'schema', key: 'field:project:name', val: { … } }
{ ns: 'schema', key: 'field:project:description', val: { … } }
{ ns: 'schema', key: 'field:project:created_at', val: { … } }
```

| Piece | Meaning |
| --- | --- |
| `key` | Stable id for a catalog object (`table::…`, `field:table:name`, and later indexes, and so on) |
| `val.source_path` | Which `.surql` file owns this definition |
| `val.file_hash` | Hash of that whole file (same as the `sync`record for the file) |
| `val.statement_hash` | Hash of this definition’s normalised statement. Used to detect “this field changed” even when other lines in the file didn’t |
| `val.state` | Lifecycle flag; `active` means SurrealKit currently expects this object to exist |

These records are what let `prune` and `rollouts` reason about individual tables and fields, not just whole files.

### `ns: 'meta'`: sync bookkeeping

```surql
{
	ns: 'meta',
	key: 'last_sync',
	val: '2026-07-16T03:49:09.93826Z',
}
```

`last_sync` records when the last sync finished. Other meta keys (like shared-database markers) can show up later once you configure shared or multi-writer setups.

### Why this matters

Part [3](https://surrealdb.com/learn/schemas/page-03)’s DIY `schema:person` history table was a manual version of the same idea. SurrealKit keeps that history for you in `__entity`: which file last won, which definitions it manages, and whether the file on disk still matches. That's why `sync` can skip unchanged files and still know what to remove when you delete a `DEFINE` from a disposable database.

## Why files instead of the shell?

| Hand-written `DEFINE` in SurrealDB Studio | SurrealKit `database/schema/` |
| --- | --- |
| Fine for exploration | Same statements, committed with your app |
| Easy to lose track of what ran where | Content hashes and per-definition records in `__entity` |
| Hard to reproduce on staging | Same files drive every environment |

As this course grows the planning schema, you'll mostly edit the `.surql` files and run sync again (or leave `sync --watch` running, which part [7](https://surrealdb.com/learn/schemas/page-07) introduces). You won't re-paste every `DEFINE` by hand when you add `activity`, relations, or indexes later.

That same file tree is what `rollouts` will plan from in part [10](https://surrealdb.com/learn/schemas/page-10): once the database is shared, you still change the files first, then generate a reviewed manifest instead of letting `sync` apply (and prune) immediately.

## Optional: connection env vars

You can store local and disposable credentials in `.env` so you can run `surrealkit sync` without flags:

```text
SURREALDB_HOST=http://localhost:8000
SURREALDB_NAMESPACE=dev
SURREALDB_NAME=planning
SURREALDB_USER=root
SURREALDB_PASSWORD=secret
```

Use a different host, namespace, or secret store for staging and production. The CLI flags and env vars have the same shape for `sync` and `rollout`; what changes is which database those variables point at, and which command you run. Until CI owns production secrets, keep shared-database credentials out of the same `.env` you use for local `sync`.

## Checkpoint

You should have:

- A `database/schema/project.surql` file with the schema you defined
- A database that answers `INFO FOR TABLE project` with your field definitions
- A sense of `sync` as “make the live catalog match these files”, with `__entity` explaining *how* SurrealKit remembers what it applied

Next: add activities on a schedule, split schema across files, and use `sync --watch` while you iterate.

Previous

5: Automation

[Previous](https://surrealdb.com/learn/schemas/page-05)

Next lesson

7: Activities and seed data

[Next lesson](https://surrealdb.com/learn/schemas/page-07)

```json
{"@context":"https://schema.org","@type":"Course","name":"Schema internals and migrations","description":"Learn how SurrealDB stores schema metadata, how DEFINE statements shape your database, and how to migrate production data safely.","url":"https://surrealdb.com/learn/schemas","inLanguage":"en","isAccessibleForFree":true,"provider":{"@type":"Organization","name":"SurrealDB","url":"https://surrealdb.com"},"hasPart":[{"@type":"LearningResource","name":"Schema internals and migrations","url":"https://surrealdb.com/learn/schemas"},{"@type":"LearningResource","name":"1: Schemaless vs. schemafull","url":"https://surrealdb.com/learn/schemas/page-01"},{"@type":"LearningResource","name":"2: Schema internals","url":"https://surrealdb.com/learn/schemas/page-02"},{"@type":"LearningResource","name":"3: Migrations","url":"https://surrealdb.com/learn/schemas/page-03"},{"@type":"LearningResource","name":"4: Data types","url":"https://surrealdb.com/learn/schemas/page-04"},{"@type":"LearningResource","name":"5: Automation","url":"https://surrealdb.com/learn/schemas/page-05"},{"@type":"LearningResource","name":"6: SurrealKit and the first table","url":"https://surrealdb.com/learn/schemas/page-06"},{"@type":"LearningResource","name":"7: Activities and seed data","url":"https://surrealdb.com/learn/schemas/page-07"},{"@type":"LearningResource","name":"8: Computed and asserted fields","url":"https://surrealdb.com/learn/schemas/page-08"},{"@type":"LearningResource","name":"9: Graph dependencies","url":"https://surrealdb.com/learn/schemas/page-09"},{"@type":"LearningResource","name":"10: Sync vs rollouts","url":"https://surrealdb.com/learn/schemas/page-10"},{"@type":"LearningResource","name":"11: Milestones","url":"https://surrealdb.com/learn/schemas/page-11"},{"@type":"LearningResource","name":"12: People and indexes","url":"https://surrealdb.com/learn/schemas/page-12"},{"@type":"LearningResource","name":"13: Events and CI","url":"https://surrealdb.com/learn/schemas/page-13"},{"@type":"LearningResource","name":"14: Capstone","url":"https://surrealdb.com/learn/schemas/page-14"}]}
```

```json
{"@context":"https://schema.org","@type":"LearningResource","name":"6: SurrealKit and the first table","description":"Initialise a SurrealKit project, define a project table, and apply schema with sync.","url":"https://surrealdb.com/learn/schemas/page-06","learningResourceType":"lesson","isPartOf":{"@type":"Course","name":"Schema internals and migrations","url":"https://surrealdb.com/learn/schemas"},"position":8}
```

```json
{"@context":"https://schema.org","@type":"Organization","name":"SurrealDB","url":"https://surrealdb.com","logo":"https://surrealdb.com/assets/static/logo.BG7_TG2b.svg","description":"SurrealDB is the unified data layer for AI. A multi-model database for documents, graphs, vectors, and time-series.","foundingDate":"2022","legalName":"SurrealDB Ltd","identifier":{"@type":"PropertyValue","propertyID":"GB-COH","value":"13615201"},"address":{"@type":"PostalAddress","streetAddress":"3rd Floor, 1 Ashley Road","addressLocality":"Altrincham","addressRegion":"Cheshire","postalCode":"WA14 2DT","addressCountry":"GB"},"contactPoint":[{"@type":"ContactPoint","contactType":"customer support","email":"support@surrealdb.com","url":"https://surrealdb.com/contact","availableLanguage":"English"},{"@type":"ContactPoint","contactType":"sales","email":"info@surrealdb.com","url":"https://surrealdb.com/contact","availableLanguage":"English"},{"@type":"ContactPoint","contactType":"security","email":"security@surrealdb.com","url":"https://surrealdb.com/.well-known/security.txt","availableLanguage":"English"},{"@type":"ContactPoint","contactType":"legal","email":"legal@surrealdb.com","url":"https://surrealdb.com/legal","availableLanguage":"English"}],"hasCertification":[{"@type":"Certification","name":"SOC 2 Type 2"},{"@type":"Certification","name":"GDPR"},{"@type":"Certification","name":"Cyber Essentials Plus"},{"@type":"Certification","name":"ISO 27001"}],"owns":[{"@type":"SoftwareApplication","name":"SurrealDB","url":"https://surrealdb.com/surrealdb"},{"@type":"SoftwareApplication","name":"Agent Memory","url":"https://surrealdb.com/agent-memory"}],"knowsAbout":["multi-model databases","document databases","graph databases","vector search","time-series databases","SurrealQL","Agent Memory","real-time databases","embedded databases","context layer","graph ontology","distributed database","knowledge graphs","distributed transaction protocols","highly-scalable databases"],"sameAs":["https://www.wikidata.org/wiki/Q124316308","https://github.com/surrealdb/surrealdb","https://twitter.com/surrealdb","https://www.youtube.com/@surrealdb","https://www.linkedin.com/company/surrealdb","https://discord.gg/surrealdb","https://www.reddit.com/r/surrealdb","https://www.instagram.com/surrealdb","https://medium.com/surrealdb","https://dev.to/surrealdb"]}
```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://surrealdb.com"},{"@type":"ListItem","position":2,"name":"Learn","item":"https://surrealdb.com/learn"},{"@type":"ListItem","position":3,"name":"Page 06","item":"https://surrealdb.com/learn/schemas/page-06"}]}
```
