Transfer & sync data across databases .md .md

This guide shows how to sync objects from a source database to your default database.

If you don’t have a database, create one:

lamin init --storage ./test-transfer --modules bionty
Hide code cell output
 initialized lamindb: anonymous/test-transfer

Import lamindb and optionally run ln.track():

import lamindb as ln

ln.track()
Hide code cell output
 connected lamindb: anonymous/test-transfer
 created Transform('jwbc1RFf0zyP0000', key='transfer.ipynb'), started new Run('Lpbna3Ea8Gc83DVJ') at 2026-07-17 13:46:28 UTC
 notebook imports: lamindb
 tip: to identify the notebook across renames, pass the uid: ln.track("jwbc1RFf0zyP")

Syncing works for any object type (Artifact, Record, Transform, ULabel, etc.). Let’s sync an artifact to our current default database:

db = ln.DB("laminlabs/lamindata")
# query the artifact on the source database
artifact = db.Artifact.get(key="example_datasets/mini_immuno/dataset1.h5ad")
# sync the artifact to the current database
artifact.save()
Hide code cell output
! database has module pertdb, configure it: lamin settings modules set bionty,pertdb
 transferred: Artifact(uid='9K1dteZ6Qx0EXK8g0000'), Storage(uid='D9BilDV2'), Schema(uid='0000000000000002')
Artifact(uid='9K1dteZ6Qx0EXK8g0000', key='example_datasets/mini_immuno/dataset1.h5ad', description='Flow cytometry readouts on invitro cell culture', suffix='.h5ad', kind='dataset', otype='AnnData', size=31672.0, hash='FB3CeMjmg1ivN6HDy6wsSg', n_files=None, n_observations=3.0, extra_data=None, branch_id=1, created_on_id=1, space_id=1, storage_id=2, run_id=2, schema_id=1, created_by_id=1, created_at=2025-07-29 12:27:25 UTC, is_locked=False, version_tag=None, is_latest=True)

If you also want to sync feature & label annotations, pass transfer="annotations":

# query again so that `artifact` holds the object on the source database
artifact = db.Artifact.get(key="example_datasets/mini_immuno/dataset1.h5ad")
# sync the artifact to the current database, including transfer of annotations where necessary
artifact.save(transfer="annotations")
Hide code cell output
 mapped: Artifact(uid='9K1dteZ6Qx0EXK8g0000'), CellType(uid='ryEtgi1yGtAcX2'), CellType(uid='22LvKd01YyNA1a'), CellType(uid='6IC9NGJEv2Y4TD'), CellType(uid='ryEtgi1yGtAcX2'), ExperimentalFactor(uid='4WYv9kl0W2SroY')
 transferred: Feature(uid='LIrjN9FbaLR1'), Feature(uid='xFdXre6ZPLlK'), Feature(uid='fJnNc4pzxe9c'), Feature(uid='7xDpJZiVLRl3'), Feature(uid='BaPfsAPgDFrT'), Feature(uid='DLeKfqUbrUsg'), Feature(uid='zvyDVbZln36o'), Feature(uid='Q8edF7CSgjG2'), Organism(uid='1dpCL6TduFJ3AP'), Source(uid='4BENqfHn'), Source(uid='404rkf5M'), Gene(uid='1j4At3x7akJU8n'), Gene(uid='6Aqvc8ckDYeNrD'), Gene(uid='3bhNYquOnA4sdo'), ULabel(uid='vmjLLqYy'), ULabel(uid='YAhFIvh5'), ULabel(uid='Yis4YLIB'), Record(uid='ZRP07Y49Ni3Ne0Ae'), Record(uid='6pjoBrrz4f1EzQMO'), Record(uid='fNBzuANAusnkFv2p'), Schema(uid='JfgNiPmWNLZz4YRh'), Feature(uid='CX6TFm8HRZu6'), ULabel(uid='oXpHlFMf'), ULabel(uid='uG3iQJMW'), ULabel(uid='wV17zBO8'), ULabel(uid='cIEobDAz'), Feature(uid='s5ESXHxwooLM'), Feature(uid='Kk5FzQyYiZfx'), Feature(uid='Lq33XwI7Wvb9'), Feature(uid='8quARuvzIzh6'), Record(uid='gOAFwv3npWr5mAcb'), Record(uid='44Yo7oClhdXccM3G'), Record(uid='JuvfAn2WCIj3R4Lj'), Record(uid='ZrOSMLb2DqPs2CYE'), Record(uid='QKdfPVGcCMH9vXh6'), Record(uid='CpFRZCHOClcQMPEo'), Record(uid='xtbOB5crJ4xYri7P'), Record(uid='QB8spmGpZYshAZdv'), Record(uid='oPpVmiUTccl8zMq6'), Record(uid='eYFpzb2584gkdfjn'), Record(uid='IANeSDKhY6Llx1D9'), Record(uid='zuwHbuHmtk6IPIF7'), Feature(uid='qAnzXs2KfkP2'), Record(uid='0uDmQZupMbjQQpwJ'), Record(uid='wW4PSdtu2qpTTdyR'), Schema(uid='JlplN7cclsdzO49n'), Feature(uid='aci5k3PxFx7f'), Feature(uid='6EhdalbSsRIj'), Feature(uid='OrUqch37OUTm'), Feature(uid='PCUQKf93Kq99'), Record(uid='TrRpxemXDzJ2wPtt'), Record(uid='Bb1Xlk8ZkYAAVfAM'), Record(uid='OQ3xUXkv8tZlA5KP'), Feature(uid='nnuGwFiO6AAn'), Feature(uid='pNaJLQh8fRA6'), Feature(uid='vjVuWauAO4Tl'), Project(uid='BZF49Wr2yZAC')
Artifact(uid='9K1dteZ6Qx0EXK8g0000', key='example_datasets/mini_immuno/dataset1.h5ad', description='Flow cytometry readouts on invitro cell culture', suffix='.h5ad', kind='dataset', otype='AnnData', size=31672, hash='FB3CeMjmg1ivN6HDy6wsSg', n_files=None, n_observations=3, extra_data=None, branch_id=1, created_on_id=1, space_id=1, storage_id=2, run_id=2, schema_id=1, created_by_id=1, created_at=2025-07-29 12:27:25 UTC, is_locked=False, version_tag=None, is_latest=True)

The artifact now has all feature & label annotations:

artifact.describe()
Hide code cell output
Artifact: example_datasets/mini_immuno/dataset1.h5ad (0000)
|   description: Flow cytometry readouts on invitro cell culture
├── uid: 9K1dteZ6Qx0EXK8g0000            run: pNkrlLu (__lamindb_transfer__/4XIuR0tvaiXM)          
kind: dataset                        otype: AnnData                                            
hash: FB3CeMjmg1ivN6HDy6wsSg         size: 30.9 KB                                             
branch: main                         space: all                                                
created_at: 2025-07-29 12:27:25 UTC  created_by: anonymous                                     
n_observations: 3                    schema: anndata_ensembl_gene_ids_and_valid_features_in_obs
├── storage/path: s3://lamindata/.lamindb/9K1dteZ6Qx0EXK8g0000.h5ad
├── Dataset features
├── obs (8)                                                                                                    
│   assay_oid                      bionty.ExperimentalFactor.ontology…  EFO:0008913                            
│   cell_type_by_expert            bionty.CellType                      CD8-positive, alpha-beta T cell        
│   cell_type_by_model             bionty.CellType                      B cell, T cell                         
│   concentration                  str                                                                         
│   donor                          str                                                                         
│   perturbation                   ULabel                               DMSO, IFNG                             
│   sample_note                    str                                                                         
│   treatment_time_h               num                                                                         
└── var.T (3 bionty.Gene)                                                                                      
    CD14                           num                                                                         
    CD4                            num                                                                         
    CD8A                           num                                                                         
├── External features
└── experiment                     Record[scRNA-seq]                    EXP-scRNA-002                          
└── Labels
    └── .ulabels                       ULabel                               DMSO, IFNG                             
        .records                       Record                               EXP-scRNA-002                          
        .projects                      Project                              Tutorials                              
        .cell_types                    bionty.CellType                      B cell, T cell, CD8-positive, alpha-be…
        .experimental_factors          bionty.ExperimentalFactor            single-cell RNA sequencing             

The sync is zero-copy, which means that the data itself remained in the original storage location:

artifact.path
Hide code cell output
S3QueryPath('lamindata/.lamindb/9K1dteZ6Qx0EXK8g0000.h5ad', protocol='s3')

Data lineage indicates the source database of the sync:

artifact.view_lineage()
Hide code cell output
! calling anonymously, will miss private instances
_images/d7c443ecd610c221d921f908fc68cb86486436ed4b931985b047609d22a05efe.svg

The run that initiated the sync is linked via initiated_by_run:

artifact.run.initiated_by_run.transform
Hide code cell output
Transform(uid='jwbc1RFf0zyP0000', key='transfer.ipynb', description='Transfer & sync data across databases [![.md](https://img.shields.io/badge/source-green)](https://github.com/laminlabs/lamindb/blob/main/docs/transfer.md)', kind='notebook', hash=None, reference=None, reference_type=None, environment=None, plan=None, branch_id=1, created_on_id=1, space_id=1, run_id=None, created_by_id=1, created_at=2026-07-17 13:46:28 UTC, is_locked=False, version_tag=None, is_latest=True)

Upon calling .save() again, lamindb identifies that the object already exists in the target database and simply maps it:

artifact = db.Artifact.get(key="example_datasets/mini_immuno/dataset1.h5ad")
artifact.save()
Hide code cell output
 mapped: Artifact(uid='9K1dteZ6Qx0EXK8g0000')
Artifact(uid='9K1dteZ6Qx0EXK8g0000', key='example_datasets/mini_immuno/dataset1.h5ad', description='Flow cytometry readouts on invitro cell culture', suffix='.h5ad', kind='dataset', otype='AnnData', size=31672, hash='FB3CeMjmg1ivN6HDy6wsSg', n_files=None, n_observations=3, extra_data=None, branch_id=1, created_on_id=1, space_id=1, storage_id=2, run_id=2, schema_id=1, created_by_id=1, created_at=2025-07-29 12:27:25 UTC, is_locked=False, version_tag=None, is_latest=True)
How do I know if an object is in the default database or elsewhere?

Every SQLRecord object has an attribute ._state.db which can take the following values:

  • None: the object has not yet been saved to any database

  • "default": the object is saved on the default database instance

  • "account/name": the object is saved on a non-default database instance referenced by account/name (e.g., laminlabs/lamindata)

Hide code cell content
# test the last 3 cells here
assert artifact.transform.description == "Transfer from `laminlabs/lamindata`"
assert artifact.transform.key == "__lamindb_transfer__/4XIuR0tvaiXM"
assert artifact.transform.uid == "4XIuR0tvaiXM0000"
assert artifact.run.initiated_by_run.transform.description.startswith("Transfer & sync data")
Hide code cell content
rm -r ./test-transfer
lamin delete --force test-transfer
! calling anonymously, will miss private instances