---
title: "Projects, archives and twins"
canonical: "https://help.twinfinity.com/space/HCFD/1642659841/Projects%2C%20archives%20and%20twins"
format: markdown
---
When you load something with the core API you are working with a source for model data. There are two
kinds of sources, and it helps to know which one you're dealing with: a **project/archive** or a
**twin**. They look similar when you list them, but they play different roles — and twins are built
*from* archives.

## The two types of model sources

|  | Project / Archive | Twin |
| --- | --- | --- |
| **What it is** | A container holding the raw files you have uploaded (IFC, DWG, PDF, …). | A model assembled according to a specification from files imported from one or more archives. |
| **What it contains** | Source files and their version history. | A ready-to-render model plus twin-level metadata (name, property sets, quantities). |
| **Versioning** | Each file is versioned on its own. | The twin itself is versioned. Every twin version pins an exact version of each file it uses. |
| **Linked to** | — | One or more archives, listed in the twin's `relatedContainerIds`. |
| **How you load it** | `getIfcChanges()` + `api.ifc.add(...)` | `TwinInput` + `api.ifc.add(...)` |

## How they relate

A twin copies files that are imported from archives named in its `relatedContainerIds` and pins an exact
version of each one. That makes a twin a **stable snapshot**: it keeps rendering the same thing even
after new files are uploaded to the archive, until a new twin version is published.

So the rule of thumb is:

- Reach for a **project/archive** when you want to work directly with the files you uploaded — pick which
IFCs to load, filter them, and so on.
- Reach for a **twin** when you want the curated, versioned model that has been built from those files,
without caring which individual files went into it. This lets you keep stable references to objects in
the model and work with the most reliable representation of the current state of the building.

## Working with projects and archives

This is the everyday case covered in [Containers and loading your digital twin](https://twinfinity.atlassian.net/wiki/spaces/HCFD/pages/378503192):
list your containers, pick the one you want, fetch its IFC files and add them to the scene.

```ts
async function loadArchive(): Promise<void> {
  const api = await getApi();

  // Containers are your projects and archives.
  const containers = await api.backend.getContainers();
  const archive = containers.find(
    (c) => c.name.toLowerCase() === 'hellotwinfinityworld'
  );

  // Set the container, but skip auto-loading geometry so we stay in control
  // of exactly what gets loaded.
  await api.setContainer(archive!, 'skip-ifc-load');

  // Fetch the IFC files in the archive and add the ones you are interested in.
  const files = await api.backend.getIfcChanges(archive!);
  await api.ifc.add(files);

  api.viewer.addOrUpdateEnvironment({ boundingInfo: api.ifc.regionBoundingInfo });
  api.viewer.camera.zoomToExtent(api.ifc.regionBoundingInfo, 'top');
}
```

`getIfcChanges()` returns the IFC files; if you need other file types (DWG, PDF, blobs, …) use the more
general `api.backend.getChanges(container, query)` with a `PredefinedBimChangeMetadataQuery`.

## Working with twins

Twins are reached through the same api client, under `api.backend.twins`. List the twins that belong to
an archive by passing that archive's container id, then load the one you want straight into the scene. A
`TwinInput` is just another input to `api.ifc.add` — exactly like an IFC file.

```ts
import { TwinInput } from '@twinfinity/core';

async function loadTwin(): Promise<void> {
  const api = await getApi();

  // List the twins related to this archive (pass its container id).
  const twins = await api.backend.twins.listAllTwins();
  const twin = twins.find((t) => t.name === 'My building');

  // Need more detail? getTwin returns the full metadata for a twin:
  // its version, related archives and property sets.
  // const details = await api.backend.twins.getTwin(twin!.id);

  // Load the latest version of the twin into the scene.
  await api.ifc.add(TwinInput.create(twin!));

  // ...or load a specific, pinned version instead:
  // await api.ifc.add(new TwinInput(twin!.id, twin!.version));

  api.viewer.addOrUpdateEnvironment({ boundingInfo: api.ifc.regionBoundingInfo });
  api.viewer.camera.zoomToExtent(api.ifc.regionBoundingInfo, 'top');
}
```

A few useful calls on `api.backend.twins`:

- `listTwins(relatedContainerId?, page?, limit?)` — a single page of twins, optionally filtered to one
archive.
- `listAllTwins(relatedContainerId?)` — the same, but auto-paginated into one array.
- `getTwin(twinId)` or `getTwin({ id, version })` — full metadata for a twin (or a specific version of
it).

> **Loading vs. inspecting.** `TwinInput` + `api.ifc.add` renders the twin's geometry in the viewer. If
> you only need its data — property sets, quantities, related archives — `getTwin` gives you that without
> loading any geometry.

> ⚠️ **Note:** Only a twin that has finished processing into a renderable model can be loaded. If you pass a
> ⚠️ twin that has no model yet, `api.ifc.add` will reject. Use the metadata from `getTwin` / `listTwins` to
> ⚠️ decide what to offer in your UI.

## In short

- Both projects/archives and twins are **model sources** you load through the core API.
- An **archive** holds your raw files; a **twin** is a versioned model built from a pinned set of those
files and linked back to its archive(s) via `relatedContainerIds`.
- Load an archive with `getIfcChanges()` → `api.ifc.add(files)`; load a twin with `TwinInput` →
`api.ifc.add(twinInput)`.
- Browse and inspect twins through `api.backend.twins`.