> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Publications

> Compute related tables from your data and make them visible together

A publication is a complete set of related tables that Bijection computes from
your own tables and makes visible in a single commit. You write the computation
as ordinary TypeScript. Bijection captures its inputs at one consistent point,
runs it, checks the output, and switches every output table to the new result at
once.

Use a publication when several derived tables must agree with each other: a list
of open orders and the per-customer totals computed from it, for example. A
reader never sees the new list next to the old totals.

Your queries read published tables like any other table:

```ts bijection/orders.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { query } from "./_generated/server";
import { v } from "bijection/values";

// Both tables always come from the same publication.
export const customerSummary = query({
  args: { customer: v.string() },
  handler: async (ctx, args) => {
    const orders = await ctx.db
      .query("open_orders")
      .withIndex("by_customer", (q) => q.eq("customer", args.customer))
      .take(100);
    const totals = await ctx.db
      .query("customer_totals")
      .withIndex("by_customer", (q) => q.eq("customer", args.customer))
      .unique();
    return { orders, totals };
  },
});
```

## How it fits together

A publication has three parts:

* [Published tables](/publications/published-tables), declared in your schema
  with `definePublished`. Their rows are written only by publication; no
  mutation can insert, patch, replace or delete them.
* A [pipeline](/publications/pipelines), declared with `defineEtl` from the
  `@bijection/pipelines` component, which you install from npm and add to
  your app with `app.use`. It names the input tables, the output tables and
  the `transform` function that turns one into the other.
* A publisher, declared with `definePublisher`. It names the internal queries
  Bijection reads to find a ready result and verify it. `defineEtl` generates
  these queries and the declaration for you.

When an input table changes, the pipeline runs again:

<Steps>
  <Step title="Capture">
    Bijection reads every input at one retained snapshot. A large input is read
    in pages, and every page comes from that same snapshot.
  </Step>

  <Step title="Transform">
    Your `transform` runs in a bounded action with no network access. Its
    result is sealed together with the exact input it received.
  </Step>

  <Step title="Check">
    The pipeline checks every output row against its table's validator, refuses
    duplicate keys, and evaluates any expectations you declared over the
    complete result.
  </Step>

  <Step title="Publish">
    Bijection recomputes the output digests from the rows it is about to write,
    and switches every output table to the new result in one commit.
  </Step>
</Steps>

## What publication guarantees

<Check>
  All output tables of a pipeline switch together. A query reads every one of
  them from the same publication.
</Check>

<Check>
  A failed run publishes nothing. The previous publication stays readable until
  a complete, checked replacement is ready.
</Check>

<Check>
  The published rows are the rows your transform produced from the captured
  input. Bijection verifies this itself; it does not trust the pipeline's own
  records.
</Check>

<Check>
  Withdrawing a publication, or revoking the authority it was published under,
  makes its tables unreadable immediately.
</Check>

Publication is asynchronous. Right after an input changes, published tables
still hold the previous result. They describe the inputs they were computed
from, not necessarily the latest state of those inputs.
[Reading publications](/publications/reading) shows how to observe which
result is serving, and how a query or mutation can require the result it
depends on.

<Note>
  Publications are bounded. A run reads at most 64 input rows, or 8,192 rows
  when one input is streamed in pages, and produces at most 65,536 output rows.
  See
  [limits](/publications/pipelines#limits) for the complete list.
</Note>

## Next steps

<CardGroup cols={3}>
  <Card title="Published tables" href="/publications/published-tables">
    Declare tables whose rows only publication can write
  </Card>

  <Card title="Pipelines" href="/publications/pipelines">
    Capture inputs, transform them and publish the result
  </Card>

  <Card title="Reading publications" href="/publications/reading">
    Query published tables and require a specific result
  </Card>
</CardGroup>
