Evolution SDK
Introduction

Import Patterns

How to choose between root, direct, and grouped imports in @evolution-sdk/evolution

Import Patterns

Evolution SDK exposes one public package with three import styles. They all reach the same consumer-facing API, but each optimizes for something different — discovery, explicitness, or grouped domains. None of them is required; choose the one that fits how you are using the SDK.

Three Ways to Import

1. Root barrel

The root barrel is the easiest place to start. Use it when you are exploring the SDK, prototyping, or reading the API through editor autocomplete.

import { , , ,  } from "@evolution-sdk/evolution"

const  = .("addr1...")
const  = .(2_000_000n)
const  = .()
  .({ : "https://cardano-preprod.blockfrost.io/api/v0", : "your-project-id" })
const  = .()

The root barrel also exports Cardano, which gives you one namespace for discovery:

import {  } from "@evolution-sdk/evolution"

const  = ..("addr1...")
const  = ..(2_000_000n)

2. Direct module import

Direct module imports are a strong default when you know the exact modules you want. Each import is explicit, tree-shakeable, and easy to search for in a codebase.

import * as  from "@evolution-sdk/evolution/Address"
import * as  from "@evolution-sdk/evolution/Assets"
import * as  from "@evolution-sdk/evolution/Transaction"

The import path matches the public module name exactly, using PascalCase. Address comes from @evolution-sdk/evolution/Address, Transaction comes from @evolution-sdk/evolution/Transaction, and so on.

3. Domain subpath

Some parts of the SDK ship as grouped domains with their own public barrel. Use these when you want several related modules from the same area.

import { , ,  } from "@evolution-sdk/evolution/plutus"
import {  } from "@evolution-sdk/evolution/blueprint"
import { ,  } from "@evolution-sdk/evolution/cose"

This style works well when the domain already has a natural namespace, such as Plutus data types, blueprint tooling, or COSE message-signing utilities.

Which One Should I Use?

Use this as a rule of thumb, not a hard rule.

SituationGood choiceWhy
Exploring the SDK in your editorRoot barrel: import { Cardano } from "@evolution-sdk/evolution"Best for autocomplete and API discovery
Writing examples or short scriptsRoot barrel: import { Address, Assets } from "@evolution-sdk/evolution"Short and convenient
Writing app code when you know the exact modules you needDirect module import: import * as Address from "@evolution-sdk/evolution/Address"Explicit and tree-shakeable
Working with Plutus-specific typesDomain subpath: import { Credential } from "@evolution-sdk/evolution/plutus"Keeps all on-chain primitive types together
Working with blueprint code generationDomain subpath: import { Codegen } from "@evolution-sdk/evolution/blueprint"All blueprint utilities live in one barrel
Working with COSE signing typesDomain subpath: import { COSESign1 } from "@evolution-sdk/evolution/cose"All signing primitives live in one barrel

What Does Not Work

Only the public entry points are supported. Deep imports into grouped subdirectories are blocked on purpose.

// Module not found
import * as Address from "@evolution-sdk/evolution/plutus/Address"
import * as Key from "@evolution-sdk/evolution/cose/Key"

Use the grouped barrel instead:

import {  } from "@evolution-sdk/evolution/plutus"
import {  } from "@evolution-sdk/evolution/cose"

Why the SDK Works This Way

The three import styles exist because no single style is right for every context.

The root barrel is the easiest entry point for discovery. A single import gives you autocomplete over the entire surface, which matters when you are learning the API or writing a quick script. The Cardano namespace goes further: it groups everything under one identifier so you can type Cardano. and browse.

Direct module imports are better for code that lives in a codebase for a long time. Each import path is a stable, searchable contract between your code and the SDK. Bundlers can tree-shake individual modules independently, so only the modules you import end up in your bundle.

Domain subpaths exist for areas of the SDK that form a coherent group — Plutus data types, COSE signing primitives, and blueprint tooling. Rather than importing each piece separately, you get one import that covers the domain.

Blocking deep imports (/plutus/Address, /cose/Key) matters because it lets the SDK reorganize internals without breaking consumers. The public entry points are the stable surface; what lives inside them is an implementation detail.

Next Steps