skills/bun-guides-ecosystem-gel/SKILL.md
Use Gel with Bun
npx skillsauth add jarle/bun-skills Bun Use Gel with BunInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Gel (formerly EdgeDB) is a graph-relational database powered by Postgres under the hood. It provides a declarative schema language, migrations system, and object-oriented query language, in addition to supporting raw SQL queries. It solves the object-relational mapping problem at the database layer, eliminating the need for an ORM library in your application code.
First, install Gel if you haven't already.
<CodeGroup> ```sh Linux/macOS terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}} curl https://www.geldata.com/sh --proto "=https" -sSf1 | sh ```irm https://www.geldata.com/ps1 | iex
brew install geldata/tap/gel-cli
</CodeGroup>
Use bun init to create a fresh project.
mkdir my-edgedb-app
cd my-edgedb-app
bun init -y
We'll use the Gel CLI to initialize a Gel instance for our project. This creates a gel.toml file in our project root.
gel project init
No `gel.toml` found in `/Users/colinmcd94/Documents/bun/fun/examples/my-gel-app` or above
Do you want to initialize a new project? [Y/n]
> Y
Specify the name of Gel instance to use with this project [default: my_gel_app]:
> my_gel_app
Checking Gel versions...
Specify the version of Gel to use with this project [default: x.y]:
> x.y
┌─────────────────────┬──────────────────────────────────────────────────────────────────┐
│ Project directory │ /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app │
│ Project config │ /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app/gel.toml│
│ Schema dir (empty) │ /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app/dbschema│
│ Installation method │ portable package │
│ Version │ x.y+6d5921b │
│ Instance name │ my_gel_app │
└─────────────────────┴──────────────────────────────────────────────────────────────────┘
Version x.y+6d5921b is already downloaded
Initializing Gel instance...
Applying migrations...
Everything is up to date. Revision initial
Project initialized.
To connect to my_gel_app, run `gel`
To see if the database is running, let's open a REPL and run a simple query.
gel
gel> select 1 + 1;
2
Then run \quit to exit the REPL.
gel> \quit
With the project initialized, we can define a schema. The gel project init command already created a dbschema/default.esdl file to contain our schema.
dbschema
├── default.esdl
└── migrations
Open that file and paste the following contents.
module default {
type Movie {
required title: str;
releaseYear: int64;
}
};
Then generate and apply an initial migration.
gel migration create
Created /Users/colinmcd94/Documents/bun/fun/examples/my-gel-app/dbschema/migrations/00001.edgeql, id: m1uwekrn4ni4qs7ul7hfar4xemm5kkxlpswolcoyqj3xdhweomwjrq
gel migrate
Applied m1uwekrn4ni4qs7ul7hfar4xemm5kkxlpswolcoyqj3xdhweomwjrq (00001.edgeql)
With our schema applied, let's execute some queries using Gel's JavaScript client library. We'll install the client library and Gel's codegen CLI, and create a seed.ts.file.
bun add gel
bun add -D @gel/generate
touch seed.ts
Paste the following code into seed.ts.
The client auto-connects to the database. We insert a couple movies using the .execute() method. We will use EdgeQL's for expression to turn this bulk insert into a single optimized query.
import { createClient } from "gel";
const client = createClient();
const INSERT_MOVIE = `
with movies := <array<tuple<title: str, year: int64>>>$movies
for movie in array_unpack(movies) union (
insert Movie {
title := movie.title,
releaseYear := movie.year,
}
)
`;
const movies = [
{ title: "The Matrix", year: 1999 },
{ title: "The Matrix Reloaded", year: 2003 },
{ title: "The Matrix Revolutions", year: 2003 },
];
await client.execute(INSERT_MOVIE, { movies });
console.log(`Seeding complete.`);
process.exit();
Then run this file with Bun.
bun run seed.ts
Seeding complete.
Gel implements a number of code generation tools for TypeScript. To query our newly seeded database in a typesafe way, we'll use @gel/generate to code-generate the EdgeQL query builder.
bunx @gel/generate edgeql-js
Generating query builder...
Detected tsconfig.json, generating TypeScript files.
To override this, use the --target flag.
Run `npx @edgedb/generate --help` for full options.
Introspecting database schema...
Writing files to ./dbschema/edgeql-js
Generation complete! 🤘
Checking the generated query builder into version control
is not recommended. Would you like to update .gitignore to ignore
the query builder directory? The following line will be added:
dbschema/edgeql-js
[y/n] (leave blank for "y")
> y
In index.ts, we can import the generated query builder from ./dbschema/edgeql-js and write a simple select query.
import { createClient } from "gel";
import e from "./dbschema/edgeql-js";
const client = createClient();
const query = e.select(e.Movie, () => ({
title: true,
releaseYear: true,
}));
const results = await query.run(client);
console.log(results);
results; // { title: string, releaseYear: number | null }[]
Running the file with Bun, we can see the list of movies we inserted.
bun run index.ts
[
{
title: "The Matrix",
releaseYear: 1999
}, {
title: "The Matrix Reloaded",
releaseYear: 2003
}, {
title: "The Matrix Revolutions",
releaseYear: 2003
}
]
For complete documentation, refer to the Gel docs.
development
Using TypeScript with Bun, including type definitions and compiler options
development
Learn how to write tests using Bun's Jest-compatible API with support for async tests, timeouts, and various test modifiers
testing
Learn how to use snapshot testing in Bun to save and compare output between test runs
testing
Learn about Bun test's runtime integration, environment variables, timeouts, and error handling