Primer

EdgeQL is the query language of EdgeDB. It’s intended as a spiritual successor to SQL that solves some of its biggest design limitations. This page is indended as a rapid-fire overview so you can hit the ground running with EdgeDB. Refer to the linked pages for more in-depth documentation.

As with most databases, you can write and execute queries as strings with one of our first-party client libraries for JavaScript, Python, Golang, and Rust, or you can execute queries over HTTP.

The examples below also demonstrate how to express the query with the TypeScript query builder, which lets you write strongly-typed EdgeQL queries in a code-first way.

Literals

EdgeQL

TypeScript

  1. db>
  1. select 'Hello there!';
  1. {'i ❤️ edgedb'}
  1. db>
  1. select "Hello there!"[0:5];
  1. {'Hello'}
  1. db>
  1. select false;
  1. {false}
  1. db>
  1. select 3.14;
  1. {3.14}
  1. db>
  1. select 12345678n;
  1. {12345678n}
  1. db>
  1. select 42e+100n;
  1. {42e100n}
  1. db>
  1. select <uuid>'a5ea6360-75bd-4c20-b69c-8f317b0d2857';
  1. {a5ea6360-75bd-4c20-b69c-8f317b0d2857}
  1. db>
  1. select <datetime>'1999-03-31T15:17:00Z';
  1. {<datetime>'1999-03-31T15:17:00Z'}
  1. db>
  1. select <duration>'5 hours 4 minutes 3 seconds';
  1. {<duration>'5:04:03'}
  1. db>
  1. select <cal::relative_duration>'2 years 18 days';
  1. {<cal::relative_duration>'P2Y18D'}
  1. db>
  1. select b'bina\\x01ry';
  1. {b'bina\\x01ry'}
  1. e.str("i ❤️ edgedb")
  2. // string
  3. e.str("hello there!").slice(0, 5)
  4. // string
  5. e.bool(false)
  6. // boolean
  7. e.int64(42)
  8. // number
  9. e.float64(3.14)
  10. // number
  11. e.bigint(BigInt(12345678))
  12. // bigint
  13. e.decimal("1234.4567")
  14. // n/a (not supported by JS clients)
  15. e.uuid("a5ea6360-75bd-4c20-b69c-8f317b0d2857")
  16. // string
  17. e.datetime("1999-03-31T15:17:00Z")
  18. // Date
  19. e.duration("5 hours 4 minutes 3 seconds")
  20. // edgedb.Duration (custom class)
  21. e.cal.relative_duration("2 years 18 days")
  22. // edgedb.RelativeDuration (custom class)
  23. e.bytes(Buffer.from("bina\\x01ry"))
  24. // Buffer

EdgeDB also supports collection types like arrays, tuples, and a json type.

EdgeQL

TypeScript

  1. db>
  1. select ['hello', 'world'];
  1. {['hello', 'world']}
  1. db>
  1. select ('Apple', 7, true);
  1. {('Apple', 7, true)}
  1. db>
  1. select (fruit := 'Apple', quantity := 3.14, fresh := true);
  1. {(fruit := 'Apple', quantity := 3.14, fresh := true)}
  1. db>
  1. select <json>["this", "is", "an", "array"];
  1. {"[\"this\", \"is\", \"an\", \"array\"]"}
  1. e.array(["hello", "world"]);
  2. // string[]
  3. e.tuple(["Apple", 7, true]);
  4. // [string, number, boolean]
  5. e.tuple({fruit: "Apple", quantity: 3.14, fresh: true});
  6. // {fruit: string; quantity: number; fresh: boolean}
  7. e.json(["this", "is", "an", "array"]);
  8. // unknown

Refer to Docs > EdgeQL > Literals for complete docs.

Functions and operators

EdgeDB provides a rich standard library of functions to operate and manipulate various data types.

EdgeQL

TypeScript

  1. db>
  1. select str_upper('oh hi mark');
  1. {'OH HI MARK'}
  1. db>
  1. select len('oh hi mark');
  1. {10}
  1. db>
  1. select uuid_generate_v1mc();
  1. {c68e3836-0d59-11ed-9379-fb98e50038bb}
  1. db>
  1. select contains(['a', 'b', 'c'], 'd');
  1. {false}
  1. e.str_upper("oh hi mark");
  2. // string
  3. e.len("oh hi mark");
  4. // number
  5. e.uuid_generate_v1mc();
  6. // string
  7. e.contains(["a", "b", "c"], "d");
  8. // boolean

Similarly, it provides a comprehensive set of built-in operators.

EdgeQL

TypeScript

  1. db>
  1. select not true;
  1. {false}
  1. db>
  1. select exists 'hi';
  1. {true}
  1. db>
  1. select 2 + 2;
  1. {4}
  1. db>
  1. select 'Hello' ++ ' world!';
  1. {'Hello world!'}
  1. db>
  1. select '😄' if true else '😢';
  1. {'😄'}
  1. db>
  1. select <duration>'5 minutes' + <duration>'2 hours';
  1. {<duration>'2:05:00'}
  1. e.op("not", e.bool(true));
  2. // booolean
  3. e.op("exists", e.set("hi"));
  4. // boolean
  5. e.op("exists", e.cast(e.str, e.set()));
  6. // boolean
  7. e.op(e.int64(2), "+", e.int64(2));
  8. // number
  9. e.op(e.str("Hello "), "++", e.str("World!"));
  10. // string
  11. e.op(e.str("😄"), "if", e.bool(true), "else", e.str("😢"));
  12. // string
  13. e.op(e.duration("5 minutes"), "+", e.duration("2 hours"))

See Docs > Standard Library for reference documentation on all built-in types, functions, and operators.

Insert an object

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  1. insert Movie {
  2. title := 'Doctor Strange 2',
  3. release_year := 2022
  4. };
  1. {default::Movie {id: 4fb990b6-0d54-11ed-a86c-9b90e88c991b}}
  1. const query = e.insert(e.Movie, {
  2. title: 'Doctor Strange 2',
  3. release_year: 2022
  4. });
  5. const result = await query.run(client);
  6. // {id: string}
  7. // by default INSERT only returns
  8. // the id of the new object

See Docs > EdgeQL > Insert.

Select objects

Use a shape to define which properties to select from the given object type.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  1. select Movie {
  2. id,
  3. title
  4. };
  1. {
  2. default::Movie {
  3. id: 4fb990b6-0d54-11ed-a86c-9b90e88c991b,
  4. title: 'Doctor Strange 2'
  5. },
  6. ...
  7. }
  1. const query = e.select(e.Movie, () => ({
  2. id: true,
  3. title: true
  4. }));
  5. const result = await query.run(client);
  6. // {id: string; title: string; }[]
  7. // To select all properties of an object, use the
  8. // spread operator with the special "*"" property:
  9. const query = e.select(e.Movie, () => ({
  10. ...e.Movie['*']
  11. }));

Fetch linked objects with a nested shape.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  6. ...
  7. ...
  1. select Movie {
  2. id,
  3. title,
  4. actors: {
  5. name
  6. }
  7. };
  1. {
  2. default::Movie {
  3. id: 9115be74-0979-11ed-8b9a-3bca6792708f,
  4. title: 'Iron Man',
  5. actors: {
  6. default::Person {name: 'Robert Downey Jr.'},
  7. default::Person {name: 'Gwyneth Paltrow'},
  8. },
  9. },
  10. ...
  11. }
  1. const query = e.select(e.Movie, () => ({
  2. id: true,
  3. title: true,
  4. actors: {
  5. name: true,
  6. }
  7. }));
  8. const result = await query.run(client);
  9. // {id: string; title: string, actors: {name: string}[]}[]

See Docs > EdgeQL > Select > Shapes.

Filtering, ordering, and pagination

The select statement can be augmented with filter, order by, offset, and limit clauses (in that order).

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  6. ...
  7. ...
  8. ...
  1. select Movie {
  2. id,
  3. title
  4. }
  5. filter .release_year > 2017
  6. order by .title
  7. offset 10
  8. limit 10;
  1. {
  2. default::Movie {
  3. id: 916425c8-0979-11ed-8b9a-e7c13d25b2ce,
  4. title: 'Shang Chi and the Legend of the Ten Rings',
  5. },
  6. default::Movie {
  7. id: 91606abe-0979-11ed-8b9a-3f9b41f42697,
  8. title: 'Spider-Man: Far From Home',
  9. },
  10. ...
  11. }
  1. const query = e.select(e.Movie, (movie) => ({
  2. id: true,
  3. title: true,
  4. filter: e.op(movie.release_year, ">", 1999),
  5. order_by: movie.title,
  6. offset: 10,
  7. limit: 10,
  8. }));
  9. const result = await query.run(client);
  10. // {id: string; title: number}[]

See Filtering, Ordering, and Pagination.

Computed properties

Selection shapes can contain computed properties.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  1. select Movie {
  2. title,
  3. title_upper := str_upper(.title),
  4. cast_size := count(.actors)
  5. };
  1. {
  2. default::Movie {
  3. title: 'Guardians of the Galaxy',
  4. title_upper: 'GUARDIANS OF THE GALAXY',
  5. cast_size: 8,
  6. },
  7. default::Movie {
  8. title: 'Avengers: Endgame',
  9. title_upper: 'AVENGERS: ENDGAME',
  10. cast_size: 30,
  11. },
  12. ...
  13. }
  1. e.select(e.Movie, movie => ({
  2. title: true,
  3. title_upper: e.str_upper(movie.title),
  4. cast_size: e.count(movie.actors)
  5. }))
  6. // {title: string; title_upper: string; cast_size: number}[]

A common use for computed properties is to query a link in reverse; this is known as a backlink and it has special syntax.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  6. ...
  1. select Person {
  2. name,
  3. acted_in := .<actors[is Content] {
  4. title
  5. }
  6. };
  1. {
  2. default::Person {
  3. name: 'Dave Bautista',
  4. acted_in: {
  5. default::Movie {title: 'Guardians of the Galaxy'},
  6. default::Movie {title: 'Guardians of the Galaxy Vol. 2'},
  7. default::Movie {title: 'Avengers: Infinity War'},
  8. default::Movie {title: 'Avengers: Endgame'},
  9. },
  10. },
  11. ...
  12. }
  1. e.select(e.Person, person => ({
  2. name: true,
  3. acted_in: e.select(person["<actors[is Content]"], () => ({
  4. title: true,
  5. })),
  6. }));
  7. // {name: string; acted_in: {title: string}[];}[]

See Docs > EdgeQL > Select > Computed and Docs > EdgeQL > Select > Backlinks.

Update objects

The update statement accepts a filter clause upfront, followed by a set shape indicating how the matching objects should be updated.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  1. update Movie
  2. filter .title = "Doctor Strange 2"
  3. set {
  4. title := "Doctor Strange in the Multiverse of Madness"
  5. };
  1. {default::Movie {id: 4fb990b6-0d54-11ed-a86c-9b90e88c991b}}
  1. const query = e.update(e.Movie, (movie) => ({
  2. filter: e.op(movie.title, '=', 'Doctor Strange 2'),
  3. set: {
  4. title: 'Doctor Strange in the Multiverse of Madness',
  5. },
  6. }));
  7. const result = await query.run(client);
  8. // {id: string}

When updating links, the set of linked objects can be added to with +=, subtracted from with -=, or overridden with :=.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  1. update Movie
  2. filter .title = "Doctor Strange 2"
  3. set {
  4. actors += (select Person filter .name = "Rachel McAdams")
  5. };
  1. {default::Movie {id: 4fb990b6-0d54-11ed-a86c-9b90e88c991b}}
  1. e.update(e.Movie, (movie) => ({
  2. filter: e.op(movie.title, '=', 'Doctor Strange 2'),
  3. set: {
  4. actors: {
  5. "+=": e.select(e.Person, person => ({
  6. filter: e.op(person.name, "=", "Rachel McAdams")
  7. }))
  8. }
  9. },
  10. }));

See Docs > EdgeQL > Update.

Delete objects

The delete statement can contain filter, order by, offset, and limit clauses.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  1. delete Movie
  2. filter .ilike "the avengers%"
  3. limit 3;
  1. {
  2. default::Movie {id: 3abe2b6e-0d2b-11ed-9ead-3745c7dfd553},
  3. default::Movie {id: 911cff40-0979-11ed-8b9a-0789a3fd4a02},
  4. default::Movie {id: 91179c12-0979-11ed-8b9a-3b5c92e7e5a5},
  5. default::Movie {id: 4fb990b6-0d54-11ed-a86c-9b90e88c991b}
  6. }
  1. const query = e.delete(e.Movie, (movie) => ({
  2. filter: e.op(movie.title, 'ilike', "the avengers%"),
  3. }));
  4. const result = await query.run(client);
  5. // {id: string}[]

See Docs > EdgeQL > Delete.

Query parameters

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  1. insert Movie {
  2. title := <str>$title,
  3. release_year := <int64>$release_year
  4. };
  1. Parameter <str>$title: Thor: Love and Thunder
  2. Parameter <int64>$release_year: 2022
  3. {default::Movie {id: 3270a2ec-0d5e-11ed-918b-eb0282058498}}
  1. const query = e.params({ title: e.str, release_year: e.int64 }, ($) => {
  2. return e.insert(e.Movie, {
  3. title: $.title,
  4. release_year: $.release_year,
  5. }))
  6. };
  7. const result = await query.run(client, {
  8. title: 'Thor: Love and Thunder',
  9. release_year: 2022,
  10. });
  11. // {id: string}

Client libraries provide a dedicated API to provide parameters when executing a query.

Javascript

Python

Go

  1. import {createClient} from "edgedb";
  2. const client = createClient();
  3. const result = await client.query(`select <str>$param`, {
  4. param: "Play it, Sam."
  5. });
  6. // => "Play it, Sam."
  1. import edgedb
  2. client = edgedb.create_async_client()
  3. async def main():
  4. result = await client.query("select <str>$param", param="Play it, Sam")
  5. # => "Play it, Sam"
  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "github.com/edgedb/edgedb-go"
  6. )
  7. func main() {
  8. ctx := context.Background()
  9. client, err := edgedb.CreateClient(ctx, edgedb.Options{})
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. defer client.Close()
  14. var (
  15. param string = "Play it, Sam."
  16. result string
  17. )
  18. query := "select <str>$0"
  19. err = client.Query(ctx, query, &result, param)
  20. // ...
  21. }

See Docs > EdgeQL > Parameters.

Subqueries

Unlike SQL, EdgeQL is composable; queries can be naturally nested. This is useful, for instance, when performing nested mutations.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  6. ...
  7. ...
  8. ...
  9. ...
  10. ...
  1. with
  2. dr_strange := (select Movie filter .title = "Doctor Strange"),
  3. benedicts := (select Person filter .name in {
  4. 'Benedict Cumberbatch',
  5. 'Benedict Wong'
  6. })
  7. update dr_strange
  8. set {
  9. actors += benedicts
  10. };
  1. {default::Movie {id: 913836ac-0979-11ed-8b9a-ef455e591c52}}
  1. // select Doctor Strange
  2. const drStrange = e.select(e.Movie, movie => ({
  3. filter: e.op(movie.title, '=', "Doctor Strange")
  4. }));
  5. // select actors
  6. const actors = e.select(e.Person, person => ({
  7. filter: e.op(person.name, 'in', e.set(
  8. 'Benedict Cumberbatch',
  9. 'Benedict Wong'
  10. ))
  11. }));
  12. // add actors to cast of drStrange
  13. const query = e.update(drStrange, ()=>({
  14. actors: { "+=": actors }
  15. }));

We can also use subqueries to fetch properties of an object we just inserted.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  6. ...
  7. ...
  1. with new_movie := (insert Movie {
  2. title := "Avengers: The Kang Dynasty",
  3. release_year := 2025
  4. })
  5. select new_movie {
  6. title, release_year
  7. };
  1. {
  2. default::Movie {
  3. title: 'Avengers: The Kang Dynasty',
  4. release_year: 2025,
  5. },
  6. }
  1. // "with" blocks are added automatically
  2. // in the generated query!
  3. const newMovie = e.insert(e.Movie, {
  4. title: "Avengers: The Kang Dynasty",
  5. release_year: 2025
  6. });
  7. const query = e.select(newMovie, ()=>({
  8. title: true,
  9. release_year: true,
  10. }));
  11. const result = await query.run(client);
  12. // {title: string; release_year: number;}

See Docs > EdgeQL > Select > Subqueries.

Polymorphic queries

Consider the following schema.

  1. abstract type Content {
  2. required property title -> str;
  3. }
  4. type Movie extending Content {
  5. property release_year -> int64;
  6. }
  7. type TVShow extending Content {
  8. property num_seasons -> int64;
  9. }

We can select the abstract type Content to simultaneously fetch all objects that extend it, and use the [is <type>] syntax to select properties from known subtypes.

EdgeQL

TypeScript

  1. db>
  2. ...
  3. ...
  4. ...
  5. ...
  1. select Content {
  2. title,
  3. [is TVShow].num_seasons,
  4. [is Movie].release_year
  5. };
  1. {
  2. default::TVShow {
  3. title: 'Wandavision',
  4. num_seasons: 1,
  5. release_year: {}
  6. },
  7. default::Movie {
  8. title: 'Iron Man',
  9. num_seasons: {},
  10. release_year: 2008
  11. },
  12. ...
  13. }
  1. const query = e.select(e.Content, (content) => ({
  2. title: true,
  3. ...e.is(e.Movie, {release_year: true}),
  4. ...e.is(e.TVShow, {num_seasons: true}),
  5. }));
  6. /* {
  7. title: string;
  8. release_year: number | null;
  9. num_seasons: number | null;
  10. }[] */

See Docs > EdgeQL > Select > Polymorphic queries.

Grouping objects

Unlike SQL, EdgeQL provides a top-level group statement to compute groupings of objects.

EdgeQL

TypeScript

  1. db>
  2. ...
  1. group Movie { title, actors: { name }}
  2. by .release_year;
  1. {
  2. {
  3. key: {release_year: 2008},
  4. grouping: {'release_year'},
  5. elements: {
  6. default::Movie { title: 'Iron Man' },
  7. default::Movie { title: 'The Incredible Hulk' },
  8. }
  9. },
  10. ...
  11. }
  1. e.group(e.Movie, (movie) => {
  2. const release_year = movie.release_year;
  3. return {
  4. title: true,
  5. by: {release_year},
  6. };
  7. });
  8. /* {
  9. grouping: string[];
  10. key: { release_year: number | null };
  11. elements: { title: string; }[];
  12. }[] */

See Docs > EdgeQL > Group.