Introduction
EdgeDB révolutionne les bases de données en 2026 en fusionnant le relationnel de PostgreSQL avec une sémantique graphe native, via EdgeQL, un langage déclaratif type-sûr. Pour les devs experts, c'est l'outil idéal pour modéliser des domaines complexes comme des réseaux sociaux ou e-commerce, où les jointures N-N explosent en SQL traditionnel. Imaginez querying un graphe de users → posts → comments en une ligne au lieu de 5 JOINs : gains de perf x10, schémas auto-migrés, et clients JS natifs. Ce tutoriel vous guide pas à pas sur un exemple concret d'app blog : installation, schéma avancé avec backlinks, CRUD optimisés, intégration Next.js, et pièges d'échelle. À la fin, vous déployez une instance prod-ready en <30min, prête pour 1M+ nœuds.
Prérequis
- Docker 24+ (pour instances isolées)
- Node.js 20+ et npm/yarn
- Connaissances avancées en TypeScript, graphes et SQL
- Git pour cloner un repo exemple (optionnel)
- 4GB RAM libre pour tests locaux
Installer EdgeDB CLI et démarrer une instance
curl --proto '=https' --tlsv1.2 -sSf https://sh edgedb.com | sh
source ~/.bashrc
edgedb instance create devblog \
--dsn postgres://edgedb@localhost:5432/postgres \
--password edgedb \
--if-not-exists
edgedb instance start devblog
edgedb -I devblog instance statusCe script télécharge l'CLI EdgeDB (version 2026 stable), crée une instance 'devblog' sur un conteneur Postgres intégré, et la démarre. Utilisez --dsn pour pointer un Postgres externe en prod ; --if-not-exists évite les doublons. Vérifiez avec status : attendez 'Ready to accept connections' pour confirmer.
Comprendre l'instance et connexion
Une instance EdgeDB encapsule un cluster Postgres avec moteur graphe. Connectez-vous via edgedb CLI ou DSN edgedb://username@localhost:10711/devblog. Pour prod, scalez avec Kubernetes : exposez port 10711, utilisez secrets pour mots de passe. Testez la connexion : edgedb -I devblog query 'SELECT 1;' doit renvoyer [{1}].
Définir le schéma de base (User et Post)
module default {
type User {
required name: str;
required email: str {
constraint exclusive;
};
posts: array of Post;
}
type Post {
required title: str;
required content: str;
required owner: User;
viewers: array of User;
}
scalar type status_t extending str {
constraint one_of('draft', 'published');
};
}Ce module .esdl définit User avec posts (array pour 1-N) et Post avec owner (required link 1:1) et viewers (N-N multi). scalar type étend str avec contraintes pour status. Sauvegardez en dbschema/default.esdl, appliquez via edgedb migration create puis edgedb migrate. Évite les pièges : toujours required pour immutables, exclusive sur emails.
Appliquer le schéma et première migration
Copiez schema.esdl dans dbschema/default.esdl. Lancez edgedb migration create --from-latest : EdgeDB génère auto une migration réversible. Appliquez avec edgedb migrate. Vérifiez : edgedb describe modules liste types. Pour itérations, EdgeDB tracke diffs et propose merges intelligents.
Insérer et query basique (CRUD User/Post)
INSERT User { name := 'Alice', email := 'alice@ex.com' };
INSERT Post { title := 'Mon premier post', content := 'Contenu...', owner := (SELECT User FILTER .email = 'alice@ex.com' LIMIT 1) };
SELECT User { name, posts: { title } } FILTER .name = 'Alice';
UPDATE Post FILTER .title = 'Mon premier post' SET { content += ' Ajouté!' };
DELETE Post FILTER .title LIKE '%premier%';Ces queries EdgeQL insertent User/Post avec link via subquery FILTER (plus safe que ID). SELECT projette nested (posts.title), UPDATE append (+=), DELETE filtre LIKE. Exécutez bloc par bloc dans edgedb. Piège : LIMIT 1 sur single link évite ambiguïtés ; utilisez @@ pour computed.
Maîtriser les relations avancées (Comment + backlinks)
Ajoutez Comment avec multi-links. Backlinks auto (.owner <- post) exposent inverse. Pour N-N viewers : ALTER TYPE Post { multi link viewers := {} ; }. Query graphe : SELECT User { posts: { viewers: { name } } } unfold tout en 1 requête.
Schéma étendu avec Comment et backlinks
using default;
abstract type Content {
required created_at: datetime { readonly := true };
};
type Comment extending Content {
required text: str;
required author: User;
required post: Post;
};
ALTER TYPE Post {
comments: array of Comment;
};
ALTER TYPE User {
authored_comments: array of Comment;
};Étends avec abstract Content pour timestamps readonly (auto-fill). Ajoute Comment linké à Post/User. Backlinks auto sur Post.comments et User.authored_comments. Migrez : edgedb migration create. Gain : queries comme SELECT Post { comments: { author: { name } } } sans JOIN.
Query experte : graphe complet avec agrégats
WITH recent_posts := (SELECT Post ORDER BY .created_at DESC LIMIT 10)
SELECT User {
name,
post_count := count(.posts),
avg_post_len := math::mean(.posts.content) ?? 0.0,
recent_posts: { title, comments: { text, author: { name } } ORDER BY .created_at }
} FILTER exists .posts
ORDER BY .post_count DESC
LIMIT 5;WITH pour CTE réutilisable, projette computed (count, math::mean), filtre exists (non-null), ordre multi-niveaux. ?? 0.0 fallback null. Exécutez après inserts : renvoie top users par posts récents avec nested comments. Perf : index auto sur created_at.
Intégrer avec client TypeScript (Next.js)
Installez @edgedb/js : npm i @edgedb/js. Créez client poolé pour scale. Dans Next.js, utilisez dans API routes ou RSC.
Client TypeScript généré et usage
import { createClient } from 'edgedb';
import e from './dbschema/edgeql-js'; // généré via edgedb gen
const client = createClient();
export async function getTopUsers() {
return e.select(e.User, (user) => ({ // type-safe!
filter_single: { name: 'Alice' },
name: true,
posts: { title: true },
}));
}
export async function createPost(userId: string, data: {title: string, content: string}) {
return e.insert(e.Post, {
title: data.title,
content: data.content,
owner: e.select(e.User, (u) => ({ filter_single: { id: userId } })),
});
}
await client.close();Générez types via npx edgedb-js codegen sur schema. Client poolé auto-gère connexions. Queries type-safe : IDE autocomplète filter_single. Usage async/await ; close() en shutdown. Piège : toujours await client.ensureConnected().
Bonnes pratiques
- Toujours générer code JS :
edgedb-js codegenpour typesafe queries, refactor-safe. - Indexez proactivement :
ALTER TYPE Post CREATE INDEX ON (.created_at)pour hot paths. - Utilisez global edges pour computed :
global current_user: User;en auth. - Migrez en CI/CD :
edgedb migrate --dev-modepuisedgedb migrate --to-revision HEAD. - Monitorez avec
edgedb instance logset Prometheus exporter intégré.
Erreurs courantes à éviter
- Oublier atomicité : EdgeDB est ACID, mais batch inserts avec
FOR ... UNIONpour perf, pas loops. - Queries non-indexées :
EXPLAINrévèle scans ; ajoutezCREATE INDEX ON (User FILTER .email). - Cardinalité mal gérée :
single linkvsmulti: erreur runtime si >1 ; utilisez?pour optional. - Migrations manuelles : jamais
RUN MIGRATIONsans review ; trust auto-gen mais validez diffs.
Pour aller plus loin
- Docs officielles : EdgeDB.com
- Repo exemple complet : GitHub EdgeDB blog
- Vidéo avancée : Queries graphe distribuées
- Formations Learni sur bases graphes : master Neo4j + EdgeDB en bootcamp.
- Communauté Discord EdgeDB pour patterns réels.