Installs into .claude/skills of the current project.
Are you the author of Obsidian Multi Env Setup?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/jeremylongshore-obsidian-multi-env-setup-364e67fc)
---
name: obsidian-multi-env-setup
description: 'Configure multiple Obsidian environments for development, testing, and
production.
Use when managing separate vaults, testing plugin versions,
or establishing a proper development workflow with isolated environments.
Trigger with phrases like "obsidian environments", "obsidian dev vault",
"obsidian testing setup", "multiple obsidian vaults".
'
allowed-tools: Read, Write, Edit, Bash(mkdir:*), Bash(ln:*)
version: 1.13.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- obsidian
- testing
- workflow
compatibility: Designed for Claude Code
---
# Obsidian Multi-Environment Setup
## Overview
Configure separate development, testing, and production vaults for Obsidian plugin work. Covers vault templates for team onboarding, environment-specific plugin settings, sync strategies, and `.obsidian/` directory management across environments.
## Prerequisites
- Obsidian desktop app installed
- Node.js 18+ and npm/pnpm for plugin builds
- Git for version control (recommended)
- Basic understanding of symlinks and file system operations
## Instructions
### Step 1: Create the Environment Structure
Set up three isolated vaults -- dev, test, and prod:
```bash
# Base directory for all environments
mkdir -p ~/obsidian-envs/{dev,test,prod}
# Dev vault: your working vault with symlinked plugin source
mkdir -p ~/obsidian-envs/dev/.obsidian/plugins/your-plugin
mkdir -p ~/obsidian-envs/dev/sandbox # scratch notes for testing
# Test vault: clean environment for QA
mkdir -p ~/obsidian-envs/test/.obsidian/plugins/your-plugin
mkdir -p ~/obsidian-envs/test/test-data
# Prod vault: mirrors real user setup
mkdir -p ~/obsidian-envs/prod/.obsidian/plugins/your-plugin
```
### Step 2: Symlink Plugin Source for Development
In the dev vault, symlink your plugin's build output so changes appear immediately:
```bash
# Remove the empty plugin directory in dev
rm -rf ~/obsidian-envs/dev/.obsidian/plugins/your-plugin
# Symlink to your plugin's repo (contains manifest.json, main.js, styles.css)
ln -s /path/to/your-plugin ~/obsidian-envs/dev/.obsidian/plugins/your-plugin
```
For hot reload during development, use the [Hot Reload plugin](https://github.com/pjeby/hot-reload):
```bash
# Clone hot-reload into dev vault's plugins
git clone https://github.com/pjeby/hot-reload.git \
~/obsidian-envs/dev/.obsidian/plugins/hot-reload
```
Then enable both your plugin and hot-reload in `.obsidian/community-plugins.json`:
```json
["your-plugin", "hot-reload"]
```
### Step 3: Environment-Specific Plugin Settings
Each vault gets its own `data.json` for your plugin. Create a config factory:
```typescript
// config/environments.ts
interface PluginConfig {
debugMode: boolean;
logLevel: 'debug' | 'info' | 'warn' | 'error';
apiEndpoint: string;
featureFlags: Record<string, boolean>;
}
const ENV_CONFIGS: Record<string, Partial<PluginConfig>> = {
dev: {
debugMode: true,
logLevel: 'debug',
apiEndpoint: 'http://localhost:3000',
featureFlags: { experimentalEditor: true, betaSync: true },
},
test: {
debugMode: true,
logLevel: 'info',
apiEndpoint: 'https://staging.api.example.com',
featureFlags: { experimentalEditor: true, betaSync: false },
},
prod: {
debugMode: false,
logLevel: 'error',
apiEndpoint: 'https://api.example.com',
featureFlags: {},
},
};
export function detectEnvironment(vaultPath: string): string {
if (vaultPath.includes('obsidian-envs/dev')) return 'dev';
if (vaultPath.includes('obsidian-envs/test')) return 'test';
return 'prod';
}
export function getConfig(env: string): PluginConfig {
const defaults: PluginConfig = {
debugMode: false,
logLevel: 'error',
apiEndpoint: '',
featureFlags: {},
};
return { ...defaults, ...ENV_CONFIGS[env] };
}
```
Use it in your plugin's `onload()`:
```typescript
async onload() {
const vaultPath = (this.app.vault.adapter as any).basePath;
const env = detectEnvironment(vaultPath);
const config = getConfig(env);
console.log(`[your-plugin] Running in ${env} mode`);
if (config.debugMode) {
// Register debug commands only in dev/test
this.addCommand({
id: 'dump-state',
name: 'Dump Plugin State (debug)',
callback: () => console.log(JSON.stringify(this.settings, null, 2)),
});
}
}
```
### Step 4: Vault Templates for Team Onboarding
Create a template vault that new team members clone:
```
vault-template/
.obsidian/
app.json # Standard app settings
appearance.json # Theme and font settings
hotkeys.json # Team-standard keybindings
community-plugins.json # Approved plugin list
plugins/ # Pre-configured plugin data.json files
dataview/data.json
templater-obsidian/data.json
templates/ # Note templates (daily, meeting, project)
daily.md
meeting.md
project-kickoff.md
README.md # Vault orientation guide
```
Script to provision a new team member's vault:
```bash
#!/bin/bash
# provision-vault.sh <username> <role>
USERNAME=$1
ROLE=${2:-editor}
VAULT_DIR=~/obsidian-team-vaults/$USERNAME
cp -r vault-template "$VAULT_DIR"
# Inject user-specific settings
cat > "$VAULT_DIR/.obsidian/plugins/rbac-plugin/data.json" <<EOF
{
"userEmail": "${USERNAME}@company.com",
"role": "${ROLE}"
}
EOF
echo "Vault provisioned at $VAULT_DIR for $USERNAME ($ROLE)"
```
### Step 5: Sync Strategies
Choose based on your team's needs:
**Git sync** (best for plugin developers):
```bash
cd ~/obsidian-envs/prod
git init
cat > .gitignore <<'EOF'
.obsidian/workspace.json
.obsidian/workspace-mobile.json
.obsidian/cache
.trash/
EOF
git add -A && git commit -m "Initial vault state"
```
Pair with the [Obsidian Git plugin](https://github.com/denolehov/obsidian-git) for auto-commit/push on a schedule.
**Obsidian Sync** (best for non-technical teams): Configure in Settings > Sync. Selective sync lets you exclude `.obsidian/plugins/` on certain devices to prevent config conflicts.
**iCloud/Dropbox** (simplest, most fragile): Place the vault inside the sync folder. Avoid editing on multiple devices simultaneously. `.obsidian/` conflicts are common -- keep a backup.
### Step 6: Managing .obsidian/ Across Environments
The `.obsidian/` directory holds all configuration. Key files and their sync behavior:
| File | Sync across envs? | Why |
|------|--------------------|-----|
| `app.json` | Yes | Core settings should be consistent |
| `appearance.json` | Yes | Theme consistency |
| `community-plugins.json` | Per-env | Dev may have debug plugins |
| `hotkeys.json` | Yes | Muscle memory matters |
| `workspace.json` | Never | Layout is per-device |
| `plugins/*/data.json` | Per-env | Settings differ by environment |
Script to sync safe configs from prod to other environments:
```bash
#!/bin/bash
# sync-config.sh -- copy safe configs from prod to dev/test
SAFE_FILES="app.json appearance.json hotkeys.json"
SRC=~/obsidian-envs/prod/.obsidian
for env in dev test; do
DST=~/obsidian-envs/$env/.obsidian
for f in $SAFE_FILES; do
cp "$SRC/$f" "$DST/$f" 2>/dev/null && echo "Synced $f to $env"
done
done
```
## Output
- Three isolated vaults (dev/test/prod) with independent plugin configurations
- Symlinked plugin source in dev vault with hot reload
- Environment detection and config switching in plugin code
- Vault template and provisioning script for team onboarding
- Sync strategy configured (Git, Obsidian Sync, or cloud)
- `.obsidian/` management scripts for consistent cross-env config
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Symlink not working | Permission denied on Windows | Run terminal as Administrator, or use `mklink /D` |
| Plugin not appearing in dev vault | Symlink target missing `manifest.json` | Run `npm run build` first; ensure `main.js` exists |
| Wrong config loaded | Vault path detection failed | Check `basePath` matches expected pattern |
| Hot reload not triggering | `.hotreload` file missing | Create empty `.hotreload` in plugin directory |
| Sync conflict on `workspace.json` | Multiple devices open same vault | Add `workspace.json` to `.gitignore` |
| Test vault has stale data | Forgot to refresh after plugin update | Copy latest build artifacts: `manifest.json`, `main.js`, `styles.css` |
## Examples
**Solo developer workflow**: Dev vault symlinked to plugin repo with hot reload. Test vault gets `npm run build` output copied in manually for final QA. Prod vault is your daily-driver vault with the released version from BRAT or community plugins.
**Team onboarding**: Run `provision-vault.sh alice editor` to create Alice's vault from the team template. She opens it in Obsidian, and all approved plugins with team-standard settings are pre-configured.
**CI testing across Obsidian versions**: Create a headless test vault with your plugin installed. Use `obsidian-cli` or Electron automation to open the vault, run plugin commands, and verify output. Repeat for each Obsidian version in your support matrix.
## Resources
- [Obsidian URI Protocol](https://help.obsidian.md/Extending+Obsidian/Obsidian+URI)
- [BRAT for Beta Testing](https://github.com/TfTHacker/obsidian42-brat)
- [Hot Reload Plugin](https://github.com/pjeby/hot-reload)
- [Obsidian Git Plugin](https://github.com/denolehov/obsidian-git)
## Next Steps
For monitoring and logging across environments, see `obsidian-observability`. For access control on shared vaults, see `obsidian-enterprise-rbac`.