.NET
Generate PDFs from .NET applications using the Format API.
Format doesn't have a dedicated .NET SDK yet, so this page outlines our recommend approach to use Format within a .NET environment.
Want a dedicated SDK?
We're exploring native SDKs for additional platforms. If this is important for your team, reach out to us.
How it works
This is our recommended workflow for .NET users.
Design
Create your PDF templates locally using Format Studio (React, Vue, or HTML).
Compile
Compile them down to a renderer bundle and assets zip using format compile. This can be done locally or in CI.
Deploy a render service
Deploy a lightweight Node.js service alongside your application. This service takes your data, renders the HTML from the compiled bundle, and calls the Format API to return the final PDF.
Call the render service
Your application sends data to the render service and receives a PDF back. No need to interact with the Format API directly.
The render service
Your compiled Format templates are JavaScript modules. The render service wraps them in a small HTTP server that accepts data, renders the HTML, and returns the PDF. You can use any server or serverless infrastructure that supports a Node runtime.
If your PDF has no dynamic data, you don't need a render service. You can call render() once after compile, save the resulting HTML to a file, and have your application send that static HTML directly to the Format API.
Here is a standalone example using Hono:
import { invoice } from './_generated'
import { FormatClient } from '@format.dev/client'
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const format = new FormatClient()
const app = new Hono()
app.post('/render/invoice', async (c) => {
const data = await c.req.json()
const doc = await invoice.render(data)
const response = await format.pdf(doc)
return new Response(response.body, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': `attachment; filename="${response.filename ?? 'document.pdf'}"`,
},
})
})
serve(app, { port: 3100 })The _generated directory (produced by format compile) is deployed alongside this service. It contains the renderer bundles and asset zips. Your application does not need access to these files.
Calling from .NET
Your .NET application sends the document data as JSON and receives a PDF stream back. The render service can run locally alongside your application or as a separate service in production (a different container, serverless function, etc.).
var renderServiceUrl = Environment.GetEnvironmentVariable("RENDER_SERVICE_URL")
?? "http://localhost:3100";
using var client = new HttpClient();
var invoiceData = new { customerName = "Ada Lovelace", invoiceNo = "INV-001" };
var response = await client.PostAsJsonAsync($"{renderServiceUrl}/render/invoice", invoiceData);
if (response.IsSuccessStatusCode)
{
await using var pdf = await response.Content.ReadAsStreamAsync();
await using var file = File.Create("./output/invoice.pdf");
await pdf.CopyToAsync(file);
}Calling the API directly
If you prefer to skip the render service and call the Format API directly from .NET, you can do so with any HTTP client.
The Format API accepts a POST request with multipart form data and returns a PDF binary stream.
POST https://api.format.dev/v1/render
Authorization: Bearer {FORMAT_API_KEY}
Content-Type: multipart/form-data| Field | Type | Description |
|---|---|---|
html | string | The rendered HTML output from your compiled template |
assets | binary (optional) | A ZIP file containing images, fonts, and static resources |
using System.Net.Http.Headers;
var apiKey = Environment.GetEnvironmentVariable("FORMAT_API_KEY");
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
using var form = new MultipartFormDataContent();
form.Add(new StringContent(html), "html");
var assetsStream = File.OpenRead("./assets.zip");
var assetsContent = new StreamContent(assetsStream);
assetsContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
form.Add(assetsContent, "assets", "assets.zip");
var response = await client.PostAsync("https://api.format.dev/v1/render", form);
if (response.IsSuccessStatusCode)
{
await using var pdf = await response.Content.ReadAsStreamAsync();
await using var file = File.Create("./output/invoice.pdf");
await pdf.CopyToAsync(file);
}This approach requires you to produce the HTML and assets yourself. See the API client reference for full details.