---
title: "7: Activities and seed data | SurrealDB University"
description: "Add the activity table, split schema files, sync --watch, and seed demo projects."
url: https://surrealdb.com/learn/schemas/page-07
---

![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)

# 7: Activities and seed data

We'll now add a new `activity` table to track tasks with a start and end time. This chapter also splits schema into multiple files, and introduces seed data kept separate from catalog definitions.

## Activity table (first cut)

You could append the next `DEFINE` statements to `database/schema/project.surql` and run `sync` again. SurrealKit would apply the new definitions the same way. A single growing file works fine for tiny schemas, but gets hard to scan once you have many tables, fields, indexes, and events.

This course keeps one file per table (or per small domain), so each chapter’s diff stays obvious and the tree stays easy to navigate. Create `database/schema/activity.surql`:

```surql
DEFINE TABLE activity SCHEMAFULL;
DEFINE FIELD name ON activity TYPE string;
DEFINE FIELD description ON activity TYPE option<string>;
DEFINE FIELD start ON activity TYPE datetime;
DEFINE FIELD end ON activity TYPE datetime;
DEFINE FIELD progress ON activity TYPE float;
```

We don't have any `COMPUTED` or `ASSERT` clauses yet. Part 8 adds those, so you can watch the schema grow file by file.

Run `sync` (or keep `watch` running, covered below):

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

You should see something like `applied database/schema/activity.surql`. Unchanged files (like `project.surql`) get skipped.

### What sync actually does

The `sync` command does more than paste `DEFINE` statements into the shell:

1. Ensure bookkeeping: apply `database/setup.surql` if needed (`__entity`, `__rollout`).
2. Hash each schema file and compare it to what `__entity` already recorded for that path.
3. Run only changed files, typically with `DEFINE … OVERWRITE` so re-applying is idempotent.
4. Update `__entity` so the next sync knows those files are current.
5. Prune: if a definition SurrealKit previously managed is missing from your files, it emits `REMOVE … IF EXISTS` (table, field, index, and so on). Deleting a `DEFINE` from a `.surql` file is therefore not a no-op. The next sync makes the live catalog match the files.

That prune step is why `sync` belongs on a disposable database, one you're happy to wipe or reshape freely: local `memory`, a throwaway data folder, a personal preview, or a CI ephemeral instance. Don't point everyday sync at staging or production, where other apps or teammates depend on the catalog.

Rollouts (part [10](https://surrealdb.com/learn/schemas/page-10)) treat removals differently: `rollout plan` records them in a reviewed manifest, `rollout start` applies non-destructive changes first, and only `rollout complete` runs the destructive `REMOVE`s after you deploy. Shared databases use that path instead of sync prune.

File hashes are SHA-256 of the file’s UTF-8 bytes, hex-encoded, computed when SurrealKit reads `database/schema/*.surql`. The helper lives in SurrealKit’s `sha256_hex` (`crates/surrealkit/src/core.rs`); disk sync builds each `SchemaFile { path, hash, sql }` in `collect_schema_files` (`crates/surrealkit/src/schema_state.rs`), then compares `hash` to `__entity` in `sync.rs`.

So after this chapter, `INFO FOR DB` lists both `project` and `activity` (plus `__entity` / `__rollout`). `INFO FOR DB` only summarises tables; field detail still lives under `INFO FOR TABLE activity`.

### Reading the second sync in `__entity`

Part [6](https://surrealdb.com/learn/schemas/page-06) left `__entity` with one `sync`record (`project.surql`) and `schema` records for `table::project` plus its fields. After this sync, inspect by namespace instead of dumping everything unordered:

```surql
SELECT key, val.hash AS hash, updated_at
	FROM __entity
	WHERE ns = 'sync'
	ORDER BY key;

SELECT key, val.source_path AS source_path, val.file_hash AS file_hash
	FROM __entity
	WHERE ns = 'schema'
	ORDER BY key;

SELECT val FROM __entity WHERE ns = 'meta' AND key = 'last_sync';
```

What you should notice:

| Signal | Typical after adding `activity.surql` |
| --- | --- |
| CLI output | `applied database/schema/activity.surql` only; `project.surql` is skipped |
| `ns = 'sync'` | New record for `database/schema/activity.surql` with a new content `hash` |
| `ns = 'sync'` | Same `database/schema/project.surql` hash as in part 6 (file untouched → not re-applied) |
| `ns = 'schema'` | New keys: `table::activity`, `field:activity:name`, `field:activity:start`, and the other activity fields |
| `ns = 'schema'` | Project keys still present; their `file_hash` / `statement_hash` stay the part-6 values |
| `ns = 'meta'` | `last_sync` moves forward to this run’s timestamp |

Example shape (hashes abbreviated):

```text
-- sync
database/schema/activity.surql  hash: 48d70d6f…1629   ← new
database/schema/project.surql   hash: 15966cde…aa3a   ← unchanged

-- schema (activity only)
table::activity
field:activity:name | description | start | end | progress
	source_path: database/schema/activity.surql
	file_hash:   48d70d6f…1629   ← same as the new sync record
```

That’s the whole point of file-level hashing: one new `.surql` file becomes one new `sync` hash plus one `schema`record per definition inside it, without replaying every other file.

Note

Prefer those filtered `SELECT`s over something like `old.diff(new)` on two full `SELECT * FROM __entity` results. Array `.diff` lines up records by `index`, and `__entity` order isn’t a stable changelog. The patch often ends up looking like `last_sync` “became” `activity.surql`, or project fields “changed” into activity fields, when the real story is just “new records were added.” Filter by `ns` / `key` / `source_path` instead.

If you snapshot `__entity` before and after for your own notes, compare sets of keys:

```surql
-- After sync: keys that belong to the new file
SELECT key FROM __entity
	WHERE ns = 'schema' AND val.source_path = 'database/schema/activity.surql';
```

## Splitting schema by domain

A common layout for this course:

```text
database/schema/
├── project.surql
└── activity.surql
```

That split is a practice choice, not a SurrealKit rule. You can also group by layer (`tables/`, `relations/`) or keep a single file until it hurts. SurrealKit applies every `.surql` file under `database/schema/` together; file order doesn’t matter as long as referenced tables exist before fields that need them. Use whatever layout keeps the catalog easy to scan as it grows.

## Sync watch during development

While you're iterating on a schema, you can set SurrealKit to check for changes every second and apply `sync` whenever one happens. SurrealKit runs until you stop it with Ctrl+C.

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

Let's give this a try by adding an unneeded field to the `project` table, saving the file, then removing it and saving the file again.

```surql
DEFINE FIELD hi ON project TYPE any;
```

You should see the following output:

```text
Watch mode active (1000ms interval). Waiting for schema changes... (Ctrl+C to stop)
Change detected and pushed: 1 schema file(s) synced, 0 stale entity(ies) pruned, 0 stale tracking file(s) removed.
Change detected and pushed: 1 schema file(s) synced, 1 stale entity(ies) pruned, 0 stale tracking file(s) removed.
```

## Seed data lives elsewhere

SurrealKit lets you keep catalog statements like `DEFINE` separate from write statements like `CREATE`. Seed data goes in `database/seed/`, not `database/schema/`.

Init left a stub at `database/seed/seed.surql` (content: `--- SEED`). SurrealKit runs every `.surql` file in the seed directory, so that stub counts toward “files found”. Delete `database/seed/seed.surql` before you add real fixtures so the seed output below matches a single demo file.

Then add the following statements to a file at `database/seed/demo_project.surql`:

```surql
CREATE project:one SET
    name = "Pad 3 expansion",
    description = "Civil and structural work";

CREATE activity:kickoff SET
    name = "Project kickoff",
    start = time::now(),
    end = time::now() + 2d,
    progress = 1.0;

CREATE activity:concrete SET
    name = "Pour concrete",
    start = time::now() + 90d,
    end = time::now() + 100d,
    progress = 0.0;
```

SurrealKit does not apply seed data during `sync`. A separate command is used to do that:

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

You should see the following output.

```text
Seeding from ./database/seed (1 files found)
  executing ./database/seed/demo_project.surql
Seeded 1 file(s); 0 unchanged
```

While similar to the `sync` command, there are a number of important differences to understand:

|  | `sync` (schema) | `seed` (data) |
| --- | --- | --- |
| Unit of change | Per definition (and per file hash) | Whole `.surql` file |
| Unchanged file | Skipped | Skipped (hashes tracked in `__seed`) |
| You edit a file | Re-applies `DEFINE` changes in the file | Re-runs every statement in that file, not just the new lines |
| You delete a `DEFINE` / `CREATE` | Sync can `REMOVE` the definition | No automatic `DELETE` of records: leftover records stay until you delete them or wipe the DB |

Seed tracks a hash per file in the `__seed` table, so running `surrealkit seed` again with nothing changed is a no-op:

```text
Seeding from ./database/seed (1 files found)
  skipping ./database/seed/demo_project.surql (unchanged)
Seeded 0 file(s); 1 unchanged
```

The catch is that the tracked unit is the whole file. Any edits made to `demo_project.surql` (even to append one new `RELATE` at the bottom) will change its hash, so the next seed re-runs **every** statement in it. With fixed ids such as `project:one`, that fails:

```text
Seeding from ./database/seed (1 files found)
  executing ./database/seed/demo_project.surql
Error: executing ./database/seed/demo_project.surql

Caused by:
    Database record `project:one` already exists
```

To make a seed file survive a re-run, write it so every statement is idempotent (`UPSERT` instead of `CREATE`, or `DELETE` then `CREATE`), or wipe the database first. `surrealkit seed --force` re-runs every file regardless of its hash, which hits the same wall for the same reason.

That’s why seed fixtures usually use fixed record ids (`project:one`, `activity:kickoff`): a re-run targets the same demo records instead of inventing new random ids each time. Seed doesn’t rewrite those records for you, and won’t turn a failing `CREATE` into an `UPDATE` or `UPSERT` automatically.

Note

Seed-file hash tracking (and the `__seed` table) arrived after the 0.7.0 release. On 0.7.0 every seed file runs on every `surrealkit seed`, so the second run fails on `project:one` immediately rather than being skipped. The practical advice here is the same either way.

Later chapters add more demo records the same way: run the new `CREATE` / `RELATE` statements by hand against the live database (or pipe the file through `surreal sql` against the same namespace), then append them to `demo_project.surql` so the next from-scratch `seed` stays complete. Don’t expect a second `surrealkit seed` to bolt new statements onto an already-seeded database.

### Mixed dumps: `--allow-all-statements`

By default SurrealKit rejects non-`DEFINE` statements in `database/schema/`. That's why this course puts `CREATE` records under `database/seed/`.

If you already have one large `.surql` dump that mixes catalog and data, and you're not ready to split it, sync can still apply the file:

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

That path is a migration aid, not the long-term layout. With the flag set, SurrealKit tracks file-level hashes only: it can't reason about individual catalog objects the way normal sync does, and pruning of individual definitions is unavailable for that run. Move `CREATE` / `INSERT` / `UPDATE` into `database/seed/` (or into rollout steps later) when you can. `REMOVE` statements stay rejected even with this flag.

See [Sync](https://surrealdb.com/docs/manage/schema-migration/sync#running-non-define-statements) for the official wording.

Activities aren't linked to the project yet. Graph relations arrive in part 9.

## Schemaless data on a schemafull table

If you `CREATE activity SET extra = "note"` before defining `extra`, a `SCHEMAFULL` table rejects the unknown field. This is the same lesson as part [1](https://surrealdb.com/learn/schemas/page-01), just caught at sync time instead of when your app sends a bad write.

## Checkpoint

- `activity.surql` alongside `project.surql`
- A second `sync` only applies the new file; `__entity` gains an activity `sync` hash and `schema` records
- `sync --watch` for local iteration
- `database/seed/` for demo records, kept separate from `DEFINE`
- `--allow-all-statements` only if you have to sync a mixed dump before splitting it up

Parts [8](https://surrealdb.com/learn/schemas/page-08) and [9](https://surrealdb.com/learn/schemas/page-09) keep practising the same gradual expansion: edit `.surql` files, sync, inspect. Part 8 tightens `activity` with `COMPUTED` / `ASSERT` / `VALUE` and ends with a single `surrealkit sync`. Part 9 adds `RELATION` tables and graph `COMPUTED` while `surrealkit sync --watch` runs in the background, so each save applies without retyping the command; stop watch with Ctrl+C once that chapter is done. Part [10](https://surrealdb.com/learn/schemas/page-10) then explains `rollouts` (the other SurrealKit path), before part [11](https://surrealdb.com/learn/schemas/page-11) adds milestones.

Previous

6: SurrealKit and the first table

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

Next lesson

8: Computed and asserted fields

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

```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":"7: Activities and seed data","description":"Add the activity table, split schema files, sync --watch, and seed demo projects.","url":"https://surrealdb.com/learn/schemas/page-07","learningResourceType":"lesson","isPartOf":{"@type":"Course","name":"Schema internals and migrations","url":"https://surrealdb.com/learn/schemas"},"position":10}
```

```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 07","item":"https://surrealdb.com/learn/schemas/page-07"}]}
```
