SQL Server Enterprise Guide
Azure AD, Always On, TDE, and compliance patterns for regulated industries. Enterprise Guide
.NET teams running SQL Server face a common problem with GraphQL tooling: most frameworks assume PostgreSQL, and adding GraphQL typically means migrating your database or running a foreign runtime.
FraiseQL is different. It generates T-SQL natively, deploys as a single binary, and integrates with the SQL Server infrastructure your team already uses — Windows Authentication, Azure AD / Entra ID, stored procedures, indexed views, and Row-Level Security.
| Before | After | |
|---|---|---|
| Database | SQL Server | SQL Server (unchanged) |
| Auth | Windows Auth / Azure AD | Windows Auth / Azure AD (unchanged) |
| Stored procedures | Used by application | Can back FraiseQL mutations |
| Views | Reporting, EF projections | FraiseQL reads from SQL views |
| Entity Framework | ORM for writes | Continues to handle writes |
| Dapper | Ad-hoc queries | Continues to run alongside |
| GraphQL API | None | FraiseQL serves it |
Your SQL Server schema does not change. Your EF migrations still run. FraiseQL adds a read-optimized GraphQL layer over SQL views you create — it doesn’t replace your existing data access patterns.
A common pattern is to keep Entity Framework for writes (mutations go through your domain logic) and use FraiseQL for complex reads (GraphQL queries that would otherwise require custom controller endpoints):
Client │ ├─── GraphQL query ──► FraiseQL ──► SQL Server view (v_order, v_customer, ...) │ └─── REST / mutation ──► .NET API ──► Entity Framework ──► SQL Server tablesFraiseQL and Entity Framework connect to the same SQL Server database. They operate independently — FraiseQL reads, EF writes. You can adopt FraiseQL incrementally, starting with one or two entities.
Assume you have an existing Orders table managed by Entity Framework:
// Existing EF modelpublic class Order{ public Guid Id { get; set; } public string Status { get; set; } public decimal Total { get; set; } public Guid CustomerId { get; set; } public DateTime CreatedAt { get; set; }}To expose orders via GraphQL:
Step 1: Create a SQL view (FraiseQL reads from views, not tables directly)
CREATE VIEW v_order ASSELECT o.id, JSON_QUERY( (SELECT CAST(o.id AS NVARCHAR(36)) AS id, o.status AS status, CAST(o.total AS FLOAT) AS total, CAST(o.customer_id AS NVARCHAR(36)) AS customerId, FORMAT(o.created_at, 'yyyy-MM-ddTHH:mm:ssZ') AS createdAt FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) ) AS dataFROM orders o;Step 2: Define the FraiseQL type
# schema.py (FraiseQL schema is defined in Python, TypeScript, or Go)import fraiseql
@fraiseql.typeclass Order: id: str status: str total: float customer_id: str created_at: str
@fraiseql.querydef orders( limit: int = 20, offset: int = 0, status: str | None = None,) -> list[Order]: return fraiseql.config(sql_source="v_order")Step 3: Configure and run
[project]name = "myapp-graphql"
[database]url = "${DATABASE_URL}"
[server]port = 8080fraiseql runResult: Your existing SQL Server data is now queryable via GraphQL:
query { orders(status: "pending", limit: 10) { id status total createdAt }}No changes to your EF migrations, domain model, or write path.
[database]url = "server=SQLSERVER01;database=myapp;integratedSecurity=true;trustServerCertificate=true"Run FraiseQL under a domain service account (DOMAIN\fraiseql-svc). The service account
needs db_datareader on the database.
[database]url = "server=myapp-sql.database.windows.net;database=myapp;Authentication=ActiveDirectoryMsi"Deploy FraiseQL to Azure Container Apps or App Service with system-assigned managed identity.
Grant the managed identity db_datareader on Azure SQL. No password anywhere in the config.
[database]url = "${DATABASE_URL}" # mssql://user:password@server:1433/databaseStore the connection string in an environment variable or Azure Key Vault. Avoid hardcoding credentials in fraiseql.toml.
Your team likely has stored procedures for write operations. FraiseQL mutations can call them directly:
-- Existing stored procedureCREATE PROCEDURE sp_update_order_status @order_id UNIQUEIDENTIFIER, @status NVARCHAR(50)ASBEGIN UPDATE orders SET status = @status WHERE id = @order_id; SELECT CAST(id AS NVARCHAR(36)) AS id, status FROM orders WHERE id = @order_id;END@fraiseql.typeclass UpdateOrderResult: id: str status: str
@fraiseql.mutationdef update_order_status(order_id: str, status: str) -> UpdateOrderResult: return fraiseql.config(fn_source="sp_update_order_status")mutation { updateOrderStatus(orderId: "...", status: "shipped") { id status }}No T-SQL rewriting. Your existing stored procedures work as-is.
services: fraiseql: image: ghcr.io/fraiseql/fraiseql:latest ports: - "8080:8080" environment: DATABASE_URL: "server=SQLSERVER01;database=myapp;integratedSecurity=true;trustServerCertificate=true" volumes: - ./fraiseql.toml:/app/fraiseql.toml:ro - ./schema.py:/app/schema.py:roFor Windows Authentication in Docker, the container must run with the domain service account’s credentials and the host must be domain-joined.
az containerapp create \ --name fraiseql \ --resource-group myapp-rg \ --environment myapp-env \ --image ghcr.io/fraiseql/fraiseql:latest \ --env-vars \ "DATABASE_URL=server=myapp-sql.database.windows.net;database=myapp;Authentication=ActiveDirectoryMsi" \ --target-port 8080 \ --ingress externalaz webapp create \ --resource-group myapp-rg \ --plan myapp-plan \ --name fraiseql-api \ --deployment-container-image-name ghcr.io/fraiseql/fraiseql:latest
az webapp config appsettings set \ --resource-group myapp-rg \ --name fraiseql-api \ --settings \ "DATABASE_URL=server=myapp-sql.database.windows.net;database=myapp;Authentication=ActiveDirectoryMsi"It can be useful to see exactly what T-SQL FraiseQL executes. Enable query logging to capture generated statements:
[server]log_queries = trueA GraphQL query like:
query { orders(status: "pending", limit: 5) { id status total }}Generates approximately:
SELECT TOP 5 dataFROM v_orderWHERE JSON_VALUE(data, '$.status') = 'pending'ORDER BY (SELECT NULL);No ORM magic. Plain T-SQL. You can run it in SSMS, add it to Query Store analysis, or add
a computed column index on $.status to speed it up.
Install FraiseQL
curl -fsSL https://install.fraiseql.dev | shfraiseql --versionCreate your first view over an existing table
Write a schema.py with your types and queries
Run
fraiseql runOpen GraphiQL at http://localhost:8080/graphql and explore your data
SQL Server Enterprise Guide
Azure AD, Always On, TDE, and compliance patterns for regulated industries. Enterprise Guide
Azure Deployment
End-to-end Azure SQL + Container Apps deployment with Managed Identity. Azure Guide
SQL Server Setup
Connection strings, schema design, and SQL Server-specific patterns. SQL Server Guide
Quick Start
General getting-started guide with installation and first API walkthrough. Quick Start