This is the official EdgeDB client library for JavaScript and TypeScript. It’s the easiest way to connect to your database and execute queries from a Node.js or Deno backend.
You can install the published database driver and optional (but recommended!) generators from npm using your package manager of choice.
$
npm install --save-prod edgedb # database driver
$
npm install --save-dev @edgedb/generate # generators
$
yarn add edgedb # database driver
$
yarn add --dev @edgedb/generate # generators
$
pnpm add --save-prod edgedb # database driver
$
pnpm add --save-dev @edgedb/generate # generators
import * as edgedb from "http://deno.land/x/edgedb/mod.ts";
This section assumes you have gone through the Quickstart Guide and understand how to update schemas, run migrations, and have
a working EdgeDB project. Let’s update the schema to make the title
property
of the Movie
type exclusive. This will help with filtering by
Movie.title
in our queries.
module default {
type Movie {
required property title -> str {
constraint exclusive;
};
multi link actors -> Person;
}
type Person {
required property name -> str;
}
}
Generate the new migration and apply them:
$
edgedb migration create
$
edgedb migrate
We’ll be using TypeScript and Node for this example, so let’s setup a simple app:
$
npm init -y # initialize a new npm project
$
npm i edgedb
$
npm i -D typescript @types/node @edgedb/generate tsx
$
npx tsc --init # initialize basic a basic TypeScript project
The Client
class implements the core functionality required to establish a
connection to your database and execute queries. If you prefer writing queries
as strings, the Client API is all you need.
Let’s create a simple Node.js script that seeds the database by running an insert query directly with the driver:
import * as edgedb from "edgedb";
const client = edgedb.createClient();
async function main() {
await client.execute(`
insert Person { name := "Robert Downey Jr." };
insert Person { name := "Scarlett Johansson" };
insert Movie {
title := <str>$title,
actors := (
select Person filter .name in {
"Robert Downey Jr.",
"Scarlett Johansson"
}
)
}
`, { title: "Iron Man 2" });
}
main();
We can now seed the database by running this script with tsx
$
npx tsx seed.ts
Feel free to explore the database in the EdgeDB UI, where you will find the new data you inserted through this script, as well as any data you inserted when running the Quickstart.
A word on module systems
Different build tools and runtimes have different specifications for how modules are imported, and we support a wide-range of those styles. For clarity, we will be sticking to standard TypeScript-style ESM module importing without a file extension throughout this documentation. Please see your build or environment tooling’s guidance on how to adapt this style.
Now, let’s write a Node.js script that queries the database for details about Iron Man 2:
import * as edgedb from "edgedb";
const client = edgedb.createClient();
async function main() {
const result = await client.querySingle(`
select Movie {
title,
actors: {
name,
}
} filter .title = "Iron Man 2"
`);
console.log(JSON.stringify(result, null, 2));
}
main();
Since we’re using TypeScript, it would be nice to be able to type the return value of this query, so let’s use our first generator, the interfaces generator to tell TypeScript what the type of our result is.
First we run the generator:
$
npx @edgedb/generate interfaces
This generator introspects your database schema and generates a set of equivalent TypeScript interfaces.
Now we can annotate our query since we are selecting the whole Movie
type:
import * as edgedb from "edgedb";
import { Movie } from "./dbschema/interfaces"
const client = edgedb.createClient();
async function main() {
// result will be inferred as Movie | null
const result = await client.querySingle<Movie>(`
select Movie {
title,
actors: {
name,
}
} filter .title = "Iron Man 2"
`);
console.log(JSON.stringify(result, null, 2));
}
main();
You can now run the script with tsx
:
$
npx tsx query.ts
Wouldn’t it be great if we could write any arbitrary query and get a type-safe
function that we could call? Good news, that’s exactly what the next generator
does! The queries generator scans your project for
*.edgeql
files and generates a file containing a strongly-typed function.
First, move the query into a separate file called getMovie.edgeql
. Next,
we’ll run the queries
generator:
$
npx @edgedb/generate queries --file
Now, let’s update our query script to call the generated function, which will provide us with type-safe querying.
import * as edgedb from "edgedb";
import { getMovie } from "./dbschema/queries"
const client = edgedb.createClient();
async function main() {
// result will be inferred as Movie | null
const result = await getMovie(client);
console.log(JSON.stringify(result, null, 2));
}
main();
Now, if you change the query to return different data, or take parameters, and run the queries generator again, the type of the newly generated function will change. It’ll be completely type safe!
At last we’ve arrived at the most powerful API for querying your EdgeDB instance: the query builder. The EdgeDB query builder provides a code-first way to write fully-typed EdgeQL queries with TypeScript. We recommend it for TypeScript users, or anyone who prefers writing queries with code.
First, we’ll run the query builder generator:
$
npx @edgedb/generate edgeql-js
Version control
The first time you run the generator, you’ll be prompted to add the generated
files to your .gitignore
. Confirm this prompt to automatically add a line
to your .gitignore
that excludes the generated files.
For consistency, we recommend omitting the generated files from version control and re-generating them as part of your deployment process. However, there may be circumstances where checking the generated files into version control is desirable, e.g. if you are building Docker images that must contain the full source code of your application.
Now, we can import the generated query builder and express our query completely in TypeScript, getting editor completion, type checking, and type inferrence:
import * as edgedb from "edgedb";
import e from "./dbschema/edgeql-js";
const client = edgedb.createClient();
async function main() {
// result will be inferred based on the query
const result = await e
.select(e.Movie, () => ({
title: true,
actors: () => ({ name: true }),
filter_single: { title: "Iron Man 2" },
}))
.run(client);
console.log(JSON.stringify(result, null, 2));
}
main();
We recommend reading the client docs first and getting
familiar with configuring the client. You’ll find important APIs like
withGlobals
and connection details there. After that, depending on your
preferences, look through the query builder documentation
and use the other pages as a reference for writing code-first EdgeDB queries.