Data API builder: a config file that turns tables into REST, GraphQL and MCP endpoints
Data API builder provides modern REST, GraphQL endpoints and MCP tools to your Azure Databases and on-prem stores.
At a glance
- What is it?
- Data API builder (DAB) is a Microsoft-published, MIT-licensed C# engine that reads a JSON config and exposes database objects over REST, GraphQL and MCP. It is genuinely convenient for read-heavy internal APIs, and the anonymous-permissions default in the getting-started path is the thing to fix before anything leaves a laptop.
- Who is it for?
- Adopt DAB when your schema is already the contract, your consumers want standard REST or GraphQL, and you would rather edit dab-config.json than write controller and resolver code for every table. Do not adopt it when your API needs a hand-shaped response contract, cross-service orchestration, or non-CRUD business logic in the request path, because the engine maps database objects, not domain operations.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem DAB solves is the boilerplate between a table and an HTTP endpoint
Most internal APIs are thin. A table exists, a client needs to read and write rows, and someone writes a controller, a DTO, a serializer and a route for each one. Data API builder removes that layer. The README describes it as an "open-source, no-code tool that creates secure, full-featured REST and GraphQL endpoints for your database", and the mechanism is literal: you describe entities in a JSON file, and the engine generates the endpoints. The audience is developers who already have a schema and want it reachable over HTTP without maintaining a translation layer, plus teams wiring MCP tools to a database for agent use. It is not aimed at anyone whose API is a product surface with its own contract. DAB is MIT licensed and the README states it is "open source and always free", which matters if you are deciding whether this becomes a dependency you cannot remove later. The supported store list is broad: Azure SQL, SQL Server, SQLDW, Cosmos DB, PostgreSQL and MySQL, and the README's environment table marks on-prem, Azure, AWS, GCP and "Other" as supported. The engine runs in a container in production and self-hosted locally in development.
A request becomes SQL through a QueryBuilder, and the config decides what exists
The README's sequence diagram names four participants: Client, Endpoint, QueryBuilder and Database. The described flow is that DAB "dynamically creates endpoints and translates requests to SQL, returning JSON". So there is no per-entity compiled code path you can inspect and patch. The entity definition in dab-config.json is the routing table, the schema mapping and the authorization policy at once. In the generated example, the Todo entity carries a source object ("dbo.Todo"), a type of "table", GraphQL naming (singular "Todo", plural "Todos"), a REST enabled flag, and a permissions array. Change the source string and the same endpoint name points somewhere else. That is the appeal and the risk: the config file is the API surface, so it belongs in review like code. The README notes that DAB supports tables, views and stored procedures, and that when the type is omitted the default is table. Views and stored procedures are where the mapping gets less mechanical, because a stored procedure is not a row set with a primary key, and the documentation is where you would need to check how each is exposed. The material here does not describe that mapping in detail, so treat it as something to verify against the docs rather than assume.
Getting from an empty folder to a running endpoint takes four commands
The path in the README is short. Install the .NET runtime version 8 or later, then install the CLI globally: dotnet tool install microsoft.dataapibuilder -g. Validate with dab --version. The CLI is described as cross-platform and "intended for local developer use", which is a hint about where it belongs in your pipeline. Initialization takes the database type, a connection string and a host mode: dab init --database-type mssql --connection-string "@env('my-connection-string')" --host-mode development. That writes dab-config.json, and the README notes the CLI assumes the file is called dab-config.json and sits in the local folder, so running from the wrong directory is a silent failure mode. The generated file sets rest.path to /api and graphql.path to /graphql, enables CORS with an empty origins list, sets authentication.provider to AppService, and leaves entities empty. Adding a table is one more command: dab add Todo --source "dbo.Todo" --permissions "anonymous:*". Then dab start. The README points at /health, /swagger and /graphql (Nitro) once it is up, and notes that --host-mode development is what enables Swagger for REST and Nitro for GraphQL. That last detail is the one to internalize: the tooling you rely on while building is tied to a mode you should not ship.
The anonymous role in the quickstart is a starting point, not a permission model
The generated Todo entity grants role "anonymous" the action "*", which the README presents plainly as part of the tutorial. It is the correct default for a five-minute demo and the wrong default for anything reachable. DAB's permission model is role-based and lives in the entities block, so authorization is per entity and per action rather than per route or per middleware. The generated host config uses AppService as the authentication provider, which ties identity to a hosting environment rather than to a token format you choose. If you are not on that environment, the provider value is one of the first things you will change, and the README does not walk through alternatives here. There is also no row-level policy visible in the entity schema shown; permissions gate the entity and the action, not which rows come back. Teams that need per-tenant filtering will be reaching for database-side mechanisms or for a service layer in front of DAB. That is a real architectural constraint, not a configuration gap. The connection string itself is handled well by default: the README recommends the @env() indirection and tells you to add .env to .gitignore, which is the right instinct, though the .env examples in the README are shell-specific and the resulting file contents shown in the documentation look mangled. Read that section carefully and write the file yourself rather than copying the echo command.
Where DAB stops being the right tool
DAB maps database objects to endpoints. That is the whole design, and it defines the boundary. If your API needs to compose three tables, call an external service, apply a business rule that depends on the caller, or return a response shape that does not match the schema, you are fighting the tool. You can push some of that into views and stored procedures, but then the database carries the logic and the config file no longer tells the whole story. The second boundary is schema evolution. Because the config references database object names, a rename or a column type change is a config change plus a client-facing change, and there is no compile step to catch it. The third is the development-to-production gap. The README is explicit that in production DAB runs in a container while in development it is locally self-hosted, and that host mode controls whether Swagger and Nitro are available. Development mode is a configuration you must consciously leave. Anyone who deploys the generated config unchanged ships anonymous full CRUD on every entity they added, with introspection enabled on the GraphQL endpoint. That is the single most likely way to get hurt by this project, and it comes from following the tutorial exactly as written.
The alternative is a thin application layer, and the difference is where the contract lives
The obvious comparison is a minimal ASP.NET Core service (or FastAPI, or Express) over the same database, using an ORM or a query builder. The difference is not performance or features. It is where the API contract lives. With DAB, the contract is derived from the schema plus the config, and it changes when either changes. With a hand-written service, the contract is code you control, and the database is an implementation detail behind it. That control costs you the boilerplate DAB eliminates: a route, a model and a serializer per resource, plus the tests to keep them honest. Choose the hand-written layer when the API is consumed by parties you do not control, when response shapes must be stable across schema migrations, or when authorization depends on data rather than on role. Choose DAB when the consumers are internal, the schema is already the contract, and the value of deleting the boilerplate outweighs the value of owning every response field. There is a middle position worth naming: put DAB behind a gateway or a small facade that handles the shaping and the policy, and let DAB do the CRUD. That keeps the config file boring and the contract in code.
Maintenance, versioning and the licence position
DAB ships as a NuGet package and a dotnet global tool, and the releases listed here include both stable and release-candidate versions, with 2.0.12 stable and 2.1.x in rc at the time of writing. That means the project is actively moving and that the rc line is available if you want to track changes early, at the cost of running pre-release code. The config schema is versioned by URL, and the generated file points at a schema release tag, so your editor's validation follows whichever version you pinned. Upgrades are therefore a package bump plus a config review, not a recompile of application code, which is cheap when it works and opaque when a default changes underneath you. The CLI, per the README, is "intended for local developer use", so treat it as a development and CI tool, not as part of your runtime. On licensing, DAB is MIT, which permits commercial and closed-source use; that is a statement about the repository's declared licence, not legal advice, and you should confirm the terms of any dependency you redistribute. The README also links a community signup form for roadmap input, which is where feature direction is discussed rather than in the repository itself.
Editorial conclusion
Adopt DAB when your schema is already the contract, your consumers want standard REST or GraphQL, and you would rather edit dab-config.json than write controller and resolver code for every table. Do not adopt it when your API needs a hand-shaped response contract, cross-service orchestration, or non-CRUD business logic in the request path, because the engine maps database objects, not domain operations. Before the first non-development deployment, run dab init without --host-mode development, replace the anonymous role in the entities block with named roles, and confirm the @env('my-connection-string') reference resolves in your target host rather than falling back to a file that is not there.
Community notes