# Custom code best practices

This guide covers best practices for using custom code effectively, avoiding common pitfalls, and working smoothly in team environments.

## When to use custom code

### Good use cases

Custom code works best for:

- **Adding utility methods** to models or SDK classes
- **Extending initialization** with custom authentication or middleware
- **Modifying configuration files** like package.json or pyproject.toml
- **Adding business logic** specific to the domain
- **Performance optimizations** that require deep changes
- **Integration code** for internal systems

### When to consider alternatives

Consider other approaches when:

- **OpenAPI can solve it**: Many customizations can be handled via OpenAPI extensions
- **Hooks suffice**: [SDK hooks](/docs/sdks/customize/code/sdk-hooks) might provide enough flexibility if you want to simply alter or act on the request or response. They are also useful for custom authentication setups

## Avoiding conflicts

### Structure changes to minimize conflicts

**Delegate logic to separate files**

Keep changes in generated files minimal to reduce merge conflicts.

```typescript
// ❌ Avoid: Writing complex logic directly in generated files

  }
}

// ✅ Better: Add new methods
class User {
  // Generated method untouched
  getName(): string {
    return this.name;
  }

  // Custom method addition
  getFullName(): string {
    return this.firstName + " " + this.lastName;
  }
}
```

## Team workflows

### Communicating changes

**Document customizations**
Create a `CUSTOMIZATIONS.md` file in the SDK:

```markdown filename="CUSTOMIZATIONS.md"
# SDK Customizations

This SDK has custom code enabled. The following customizations have been added:

## Utility Methods
- `Payment.toInvoiceItem()` - Converts payments to invoice format
- `User.getFullName()` - Returns formatted full name

## Custom Dependencies
- `aws-sdk` - For S3 upload functionality
- `redis` - For caching API responses

## Modified Files
- `src/models/payment.ts` - Added utility methods
- `package.json` - Added custom dependencies and scripts
```

**Use clear commit messages**
```bash
# When adding customizations
git commit -m "feat(sdk): add payment utility methods for invoice conversion"

# When resolving conflicts
git commit -m "fix(sdk): resolve generation conflicts in payment model"
```

## Troubleshooting tips

### Common patterns to avoid

**Do not remove generated headers**
```typescript
// ❌ Do not remove these
// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
// @generated-id: a1b2c3d4e5f6

// ✅ Keep them for move detection to work
```

**Do not copy files with IDs**
```bash
# ❌ Copying creates duplicate IDs
cp src/models/user.ts src/models/user-v2.ts

# ✅ Either move or create new file
mv src/models/user.ts src/models/user-v2.ts
# or create fresh without the @generated-id header
```

### Recovery procedures

**Reset a single file**
```bash
# Remove custom changes from one file
git checkout HEAD -- src/models/payment.ts

# Re-run generation using the same pristine snapshot (no new snapshot is created)
speakeasy run --skip-versioning
```

**Reset everything**
```bash
# Disable custom code
# Edit .speakeasy/gen.yaml: enabled: false

# Remove all generated files
find . -name "*.gen.*" -delete  # Adjust pattern for the SDK

# Regenerate fresh
speakeasy run
```

**Fix "duplicate ID" warnings**
1. Find files with duplicate IDs
2. Remove `@generated-id` line from copied files
3. Let next generation assign new IDs

## Summary checklist

<Callout title="Quick reference" type="info">
✓ Enable custom code before reorganizing files. Move detection is file-specific, not folder-specific
✓ Document customizations for team members
✓ Do not remove @generated-id headers
✓ Commit custom edits independently of generator changes for clarity
</Callout>
