diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts
index e944d9c8d93060cb76f250996a056c293040050d..9dc2185554d02c35b7130e06baf8640f62f908b3 100644
--- a/src/mol-model/structure/model/formats/mmcif.ts
+++ b/src/mol-model/structure/model/formats/mmcif.ts
@@ -24,6 +24,7 @@ import { getSequence } from './mmcif/sequence';
 import { sortAtomSite } from './mmcif/sort';
 
 import mmCIF_Format = Format.mmCIF
+import { StructConn } from './mmcif/bonds/struct_conn';
 
 type AtomSite = mmCIF_Database['atom_site']
 
@@ -166,6 +167,7 @@ function createModelIHM(format: mmCIF_Format, data: IHMData): Model {
 
 function attachProps(model: Model) {
     ComponentBond.attachFromMmCif(model);
+    StructConn.attachFromMmCif(model);
 }
 
 function findModelEnd(num: Column<number>, startIndex: number) {
diff --git a/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts b/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts
index 04d74a0a7910dc3643e785f912e1f2eba400f829..b89b473df9e6dfccb1d0732099290c60a1c4382d 100644
--- a/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts
+++ b/src/mol-model/structure/model/formats/mmcif/bonds/comp.ts
@@ -24,11 +24,10 @@ export namespace ComponentBond {
         cifExport: {
             categoryNames: ['chem_comp_bond'],
             categoryProvider(ctx) {
-                const comp_names = getUniqueResidueNames(ctx.structure);
                 const chem_comp_bond = getChemCompBond(ctx.model);
-
                 if (!chem_comp_bond) return [];
 
+                const comp_names = getUniqueResidueNames(ctx.structure);
                 const { comp_id, _rowCount } = chem_comp_bond;
                 const indices: number[] = [];
                 for (let i = 0; i < _rowCount; i++) {
@@ -95,7 +94,7 @@ export namespace ComponentBond {
         if (!model.customProperties.has(Descriptor)) return void 0;
         const chem_comp_bond = getChemCompBond(model);
 
-        let compBond = new ComponentBondImpl();
+        const compBond = new ComponentBondImpl();
 
         const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount: rowCount } = chem_comp_bond;
 
diff --git a/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts b/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts
index d0c0e5f07e0ab70bc4db546a0dcc68395a06b5d4..f2ea4703a18f1ef90982750a70c37a1036e963ab 100644
--- a/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts
+++ b/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts
@@ -6,17 +6,68 @@
  */
 
 import Model from '../../../model'
-import { Element } from '../../../../structure'
+import { Element, Structure } from '../../../../structure'
 import { LinkType } from '../../../types'
 import { findEntityIdByAsymId, findAtomIndexByLabelName } from '../util'
 import { Column } from 'mol-data/db'
+import { ModelPropertyDescriptor } from '../../../properties/custom';
+import { mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif';
+import { SortedArray } from 'mol-data/int';
+import { CifWriter } from 'mol-io/writer/cif'
 
 export interface StructConn {
-    getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConn.Entry>
-    getAtomEntries(atomIndex: number): ReadonlyArray<StructConn.Entry>
+    getResidueEntries(residueAIndex: number, residueBIndex: number): ReadonlyArray<StructConn.Entry>,
+    getAtomEntries(atomIndex: number): ReadonlyArray<StructConn.Entry>,
+    readonly entries: ReadonlyArray<StructConn.Entry>
 }
 
 export namespace StructConn {
+    export const Descriptor: ModelPropertyDescriptor = {
+        isStatic: true,
+        name: 'struct_conn',
+        cifExport: {
+            categoryNames: ['struct_conn'],
+            categoryProvider(ctx) {
+                const struct_conn = getStructConn(ctx.model);
+                if (!struct_conn) return [];
+
+                const strConn = get(ctx.model);
+                if (!strConn || strConn.entries.length === 0) return [];
+
+                const foundAtoms = new Set<Element>();
+                const indices: number[] = [];
+                for (const entry of strConn.entries) {
+                    const { partners } = entry;
+                    let hasAll = true;
+                    for (let i = 0, _i = partners.length; i < _i; i++) {
+                        const atom = partners[i].atomIndex;
+                        if (foundAtoms.has(atom)) continue;
+                        if (hasAtom(ctx.structure, atom)) {
+                            foundAtoms.add(atom);
+                        } else {
+                            hasAll = false;
+                            break;
+                        }
+                    }
+                    if (hasAll) {
+                        indices[indices.length] = entry.rowIndex;
+                    }
+                }
+
+                return [
+                    () => CifWriter.Category.ofTable('struct_conn', struct_conn, indices)
+                ];
+            }
+        }
+    }
+
+    function hasAtom({ units }: Structure, element: Element) {
+        for (let i = 0, _i = units.length; i < _i; i++) {
+            if (SortedArray.indexOf(units[i].elements, element) >= 0) return true;
+        }
+        return false;
+    }
+
     function _resKey(rA: number, rB: number) {
         if (rA < rB) return `${rA}-${rB}`;
         return `${rB}-${rA}`;
@@ -77,6 +128,7 @@ export namespace StructConn {
     }
 
     export interface Entry {
+        rowIndex: number,
         distance: number,
         order: number,
         flags: number,
@@ -95,19 +147,33 @@ export namespace StructConn {
         | 'modres'
         | 'saltbr'
 
+    export function attachFromMmCif(model: Model): boolean {
+        if (model.customProperties.has(Descriptor)) return true;
+        if (model.sourceData.kind !== 'mmCIF') return false;
+        const { struct_conn } = model.sourceData.data;
+        if (struct_conn._rowCount === 0) return false;
+        model.customProperties.add(Descriptor);
+        model._staticPropertyData.__StructConnData__ = struct_conn;
+        return true;
+    }
+
+    function getStructConn(model: Model) {
+        return model._staticPropertyData.__StructConnData__ as mmCIF_Database['struct_conn'];
+    }
+
     export const PropName = '__StructConn__';
-    export function fromModel(model: Model): StructConn | undefined {
+    export function get(model: Model): StructConn | undefined {
         if (model._staticPropertyData[PropName]) return model._staticPropertyData[PropName];
+        if (!model.customProperties.has(Descriptor)) return void 0;
 
-        if (model.sourceData.kind !== 'mmCIF') return;
-        const { struct_conn } = model.sourceData.data;
-        if (!struct_conn._rowCount) return void 0;
+        const struct_conn = getStructConn(model);
 
         const { conn_type_id, pdbx_dist_value, pdbx_value_order } = struct_conn;
         const p1 = {
             label_asym_id: struct_conn.ptnr1_label_asym_id,
             label_comp_id: struct_conn.ptnr1_label_comp_id,
             label_seq_id: struct_conn.ptnr1_label_seq_id,
+            auth_seq_id: struct_conn.ptnr1_auth_seq_id,
             label_atom_id: struct_conn.ptnr1_label_atom_id,
             label_alt_id: struct_conn.pdbx_ptnr1_label_alt_id,
             ins_code: struct_conn.pdbx_ptnr1_PDB_ins_code,
@@ -117,6 +183,7 @@ export namespace StructConn {
             label_asym_id: struct_conn.ptnr2_label_asym_id,
             label_comp_id: struct_conn.ptnr2_label_comp_id,
             label_seq_id: struct_conn.ptnr2_label_seq_id,
+            auth_seq_id: struct_conn.ptnr2_auth_seq_id,
             label_atom_id: struct_conn.ptnr2_label_atom_id,
             label_alt_id: struct_conn.pdbx_ptnr2_label_alt_id,
             ins_code: struct_conn.pdbx_ptnr2_PDB_ins_code,
@@ -128,9 +195,9 @@ export namespace StructConn {
             const asymId = ps.label_asym_id.value(row)
             const residueIndex = model.atomicHierarchy.findResidueKey(
                 findEntityIdByAsymId(model, asymId),
-                ps.label_comp_id.value(row),
                 asymId,
-                ps.label_seq_id.value(row),
+                ps.label_comp_id.value(row),
+                ps.auth_seq_id.value(row),
                 ps.ins_code.value(row)
             );
             if (residueIndex < 0) return void 0;
@@ -182,7 +249,7 @@ export namespace StructConn {
                 case 'saltbr': flags = LinkType.Flag.Ion; break;
             }
 
-            entries.push({ flags, order, distance: pdbx_dist_value.value(i), partners });
+            entries.push({ rowIndex: i, flags, order, distance: pdbx_dist_value.value(i), partners });
         }
 
         const ret = new StructConnImpl(entries);
diff --git a/src/mol-model/structure/model/formats/mmcif/util.ts b/src/mol-model/structure/model/formats/mmcif/util.ts
index 2bccf1a97fb9209d8250ebc4b726447bb29214d3..672acf2efc9049c90a361e289088ce1240100c8b 100644
--- a/src/mol-model/structure/model/formats/mmcif/util.ts
+++ b/src/mol-model/structure/model/formats/mmcif/util.ts
@@ -17,10 +17,9 @@ export function findEntityIdByAsymId(model: Model, asymId: string) {
 }
 
 export function findAtomIndexByLabelName(model: Model, residueIndex: number, atomName: string, altLoc: string | null): Element {
-    const { segmentMap, segments } = model.atomicHierarchy.residueSegments
-    const idx = segmentMap[residueIndex]
+    const { segments } = model.atomicHierarchy.residueSegments;
     const { label_atom_id, label_alt_id } = model.atomicHierarchy.atoms;
-    for (let i = segments[idx], n = segments[idx + 1]; i <= n; ++i) {
+    for (let i = segments[residueIndex], n = segments[residueIndex + 1]; i < n; ++i) {
         if (label_atom_id.value(i) === atomName && (!altLoc || label_alt_id.value(i) === altLoc)) return i as Element;
     }
     return -1 as Element;
diff --git a/src/mol-model/structure/model/properties/atomic/hierarchy.ts b/src/mol-model/structure/model/properties/atomic/hierarchy.ts
index 513f36110ba1dee18369d89d4a045d90a0144ae6..f03c8521349e6fa316d2b97c870ffad4b7425920 100644
--- a/src/mol-model/structure/model/properties/atomic/hierarchy.ts
+++ b/src/mol-model/structure/model/properties/atomic/hierarchy.ts
@@ -48,7 +48,9 @@ export interface AtomicData {
 }
 
 export interface AtomicSegments {
+    /** Maps residueIndex to a range of atoms [segments[rI], segments[rI + 1]) */
     residueSegments: Segmentation<Element>,
+    /** Maps chainIndex to a range of atoms [segments[cI], segments[cI + 1]) */
     chainSegments: Segmentation<Element>
     // TODO: include entity segments?
 }
diff --git a/src/mol-model/structure/structure/unit/links/inter-compute.ts b/src/mol-model/structure/structure/unit/links/inter-compute.ts
index 40eb99a7a87d94f7da5d007def10c286b4db1590..bc1dd6becd6a954511d6b10948acaea5df43d999 100644
--- a/src/mol-model/structure/structure/unit/links/inter-compute.ts
+++ b/src/mol-model/structure/structure/unit/links/inter-compute.ts
@@ -45,7 +45,7 @@ function findPairLinks(unitA: Unit.Atomic, unitB: Unit.Atomic, params: LinkCompu
     const { type_symbol: type_symbolA, label_alt_id: label_alt_idA } = unitA.model.atomicHierarchy.atoms;
     const { type_symbol: type_symbolB, label_alt_id: label_alt_idB } = unitB.model.atomicHierarchy.atoms;
     const { lookup3d } = unitB;
-    const structConn = unitA.model === unitB.model && unitA.model.sourceData.kind === 'mmCIF' ? StructConn.fromModel(unitA.model) : void 0;
+    const structConn = unitA.model === unitB.model && unitA.model.sourceData.kind === 'mmCIF' ? StructConn.get(unitA.model) : void 0;
 
     for (let _aI = 0; _aI < atomCount; _aI++) {
         const aI =  atomsA[_aI];