# How startup.json is Loaded and Used on Startup

## YES - The code DOES check startup.json on startup! ✅

Here's the complete flow:

---

## Startup Flow Diagram

```
┌─────────────────────────────────────────────┐
│ 1. Jellyfin Starts                          │
│    Program.Main() → StartApp()              │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│ 2. CreateApplicationPaths()                 │
│    (in StartupHelpers.cs)                   │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│ 3. LoadStartupConfiguration()               │
│    Searches for startup.json in:            │
│    • Current directory                      │
│    • AppContext.BaseDirectory               │
│    • AppContext.BaseDirectory/config        │
└──────────────────┬──────────────────────────┘
                   │
         ┌─────────┴─────────┐
         │                   │
    Found? Yes              No
         │                   │
         ▼                   ▼
┌──────────────────┐  ┌───────────────────────┐
│ 4a. Load JSON    │  │ 4b. Create Default    │
│     Return config│  │     (OS-specific)     │
└────────┬─────────┘  └───────────┬───────────┘
         │                        │
         └────────────┬───────────┘
                      │
                      ▼
┌─────────────────────────────────────────────┐
│ 5. Resolve Paths (Priority Order):         │
│    1. Command-line args                     │
│    2. Environment variables                 │
│    3. startup.json values ← HERE!           │
│    4. Built-in defaults                     │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│ 6. Create ServerApplicationPaths object     │
│    with resolved paths                      │
└─────────────────────────────────────────────┘
```

---

## Code Flow Details

### Step 1: Startup Entry Point
**File:** `Jellyfin.Server/Program.cs`

```csharp
// Line 88-90
private static async Task StartApp(StartupOptions options)
{
    ServerApplicationPaths appPaths = StartupHelpers.CreateApplicationPaths(options);
    // ...
}
```

### Step 2: Load Configuration
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`

```csharp
// Line 222-223
public static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
{
    // Try to load startup configuration from file
    var startupConfig = LoadStartupConfiguration();
    // ...
}
```

### Step 3: Search for startup.json
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`

```csharp
// Lines 78-112
private static IConfigurationRoot? LoadStartupConfiguration()
{
    const string ConfigFileName = "startup.json";

    // Search locations in priority order
    var searchPaths = new[]
    {
        Path.Combine(Directory.GetCurrentDirectory(), ConfigFileName),
        Path.Combine(AppContext.BaseDirectory, ConfigFileName),
        Path.Combine(AppContext.BaseDirectory, "config", ConfigFileName)
    };

    foreach (var configPath in searchPaths)
    {
        if (File.Exists(configPath))
        {
            try
            {
                var config = new ConfigurationBuilder()
                    .AddJsonFile(configPath, optional: false, reloadOnChange: false)
                    .Build();

                Console.WriteLine($"Loaded startup configuration from: {configPath}");
                return config;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Warning: Failed to load startup configuration from {configPath}: {ex.Message}");
            }
        }
    }

    // No configuration file found - create a default one
    CreateDefaultStartupConfiguration();
    return null;
}
```

### Step 4: Use startup.json Values
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`

Each path is resolved with this priority chain:

```csharp
// DataDir example (lines 230-234)
var dataDir = options.DataDir                                    // 1. Command-line
    ?? Environment.GetEnvironmentVariable("JELLYFIN_DATA_DIR")  // 2. Environment
    ?? startupConfig?.GetValue<string>("Paths:DataDir")         // 3. startup.json ← HERE!
    ?? Path.Join(                                               // 4. Built-in default
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
        "jellyfin");

// ConfigDir (lines 236-248)
var configDir = options.ConfigDir
    ?? Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR")
    ?? startupConfig?.GetValue<string>("Paths:ConfigDir");      // ← startup.json checked!

// CacheDir (lines 250-260)
var cacheDir = options.CacheDir
    ?? Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR")
    ?? startupConfig?.GetValue<string>("Paths:CacheDir");       // ← startup.json checked!

// LogDir (lines 289-293)
var logDir = options.LogDir
    ?? Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR")
    ?? startupConfig?.GetValue<string>("Paths:LogDir");         // ← startup.json checked!

// TempDir (lines 295-301)
var tempDir = options.TempDir
    ?? Environment.GetEnvironmentVariable("JELLYFIN_TEMP_DIR")
    ?? startupConfig?.GetValue<string>("Paths:TempDir");        // ← startup.json checked!

// WebDir (lines 262-287)
var webDir = options.WebDir
    ?? Environment.GetEnvironmentVariable("JELLYFIN_WEB_DIR")
    ?? startupConfig?.GetValue<string>("Paths:WebDir");         // ← startup.json checked!
```

---

## Search Locations (In Order)

When looking for `startup.json`, the code checks these locations:

1. **Current working directory**
   - Example: `E:\Projects\pgsql-jellyfin\startup.json`
   - This is where you run `jellyfin` from

2. **Application base directory**
   - Example: `E:\Projects\pgsql-jellyfin\Jellyfin.Server\bin\Release\net11.0\startup.json`
   - Where the jellyfin.exe/dll is located

3. **Config subdirectory**
   - Example: `E:\Projects\pgsql-jellyfin\Jellyfin.Server\bin\Release\net11.0\config\startup.json`
   - Allows organizing config files

---

## Priority Order for Path Resolution

For **each path** (DataDir, ConfigDir, etc.), the code checks in this order:

```
┌──────────────────────────────────────┐
│ 1. Command-line argument             │  Highest Priority
│    --datadir /custom/path            │  (Always wins)
└──────────────────┬───────────────────┘
                   │ If not provided
                   ▼
┌──────────────────────────────────────┐
│ 2. Environment variable              │
│    JELLYFIN_DATA_DIR=/custom/path    │
└──────────────────┬───────────────────┘
                   │ If not set
                   ▼
┌──────────────────────────────────────┐
│ 3. startup.json value                │  ← YOUR QUESTION!
│    "DataDir": "/custom/path"         │  YES, IT CHECKS HERE!
└──────────────────┬───────────────────┘
                   │ If null or missing
                   ▼
┌──────────────────────────────────────┐
│ 4. Built-in OS-specific default      │  Lowest Priority
│    (code determines based on OS)     │  (Fallback)
└──────────────────────────────────────┘
```

---

## Console Output

### When startup.json is Found
```
Loaded startup configuration from: E:\Projects\pgsql-jellyfin\startup.json
```

### When startup.json is Not Found
```
Created default startup configuration at: E:\Projects\pgsql-jellyfin\startup.json
Using Windows defaults - using C:/ProgramData/jellyfin
You can customize this file to set different paths for Jellyfin.
```

---

## Real-World Examples

### Example 1: Using startup.json

**Your startup.json:**
```json
{
  "Paths": {
    "DataDir": "D:/Media/Jellyfin/Data",
    "ConfigDir": "D:/Media/Jellyfin/Config",
    "CacheDir": "E:/Cache/Jellyfin",
    "LogDir": "D:/Logs/Jellyfin"
  }
}
```

**What happens on startup:**
```csharp
// For DataDir:
options.DataDir                               // null (not provided)
?? Environment.GetEnvironmentVariable(...)    // null (not set)
?? startupConfig?.GetValue("Paths:DataDir")  // "D:/Media/Jellyfin/Data" ← USED!

// Result: DataDir = "D:/Media/Jellyfin/Data"
```

**Console output:**
```
Loaded startup configuration from: E:\Projects\pgsql-jellyfin\startup.json
[INF] Data directory: D:/Media/Jellyfin/Data
[INF] Config directory: D:/Media/Jellyfin/Config
[INF] Cache directory: E:/Cache/Jellyfin
[INF] Log directory: D:/Logs/Jellyfin
```

### Example 2: Override with Command-Line

**Your startup.json:**
```json
{
  "Paths": {
    "DataDir": "D:/Media/Jellyfin/Data"
  }
}
```

**Command:**
```powershell
jellyfin --datadir "F:/CustomData"
```

**What happens:**
```csharp
options.DataDir                               // "F:/CustomData" ← USED! (highest priority)
?? Environment.GetEnvironmentVariable(...)    // (not checked)
?? startupConfig?.GetValue("Paths:DataDir")  // (not checked)

// Result: DataDir = "F:/CustomData"
```

### Example 3: Override with Environment Variable

**Your startup.json:**
```json
{
  "Paths": {
    "DataDir": "D:/Media/Jellyfin/Data"
  }
}
```

**Environment:**
```powershell
$env:JELLYFIN_DATA_DIR = "G:/EnvData"
jellyfin
```

**What happens:**
```csharp
options.DataDir                               // null
?? Environment.GetEnvironmentVariable(...)    // "G:/EnvData" ← USED!
?? startupConfig?.GetValue("Paths:DataDir")  // (not checked)

// Result: DataDir = "G:/EnvData"
```

---

## Testing the Behavior

### Test 1: Verify startup.json is Loaded
```powershell
# Create a test startup.json
@"
{
  "Paths": {
    "DataDir": "E:/TEST_JELLYFIN_DATA",
    "LogDir": "E:/TEST_JELLYFIN_LOGS"
  }
}
"@ | Out-File startup.json

# Run Jellyfin (it will create these directories and use them)
.\jellyfin.exe

# Check console output - should see:
# "Loaded startup configuration from: E:\Projects\pgsql-jellyfin\startup.json"
```

### Test 2: Verify Priority Order
```powershell
# Set in startup.json
echo '{"Paths":{"DataDir":"E:/FROM_JSON"}}' > startup.json

# Override with environment variable
$env:JELLYFIN_DATA_DIR = "E:/FROM_ENV"

# Run Jellyfin
.\jellyfin.exe

# Result: Will use E:/FROM_ENV (environment wins over startup.json)
```

### Test 3: Verify Search Locations
```powershell
# Put startup.json in current directory
echo '{"Paths":{"DataDir":"E:/CURRENT_DIR"}}' > startup.json

# Also put one in base directory
echo '{"Paths":{"DataDir":"E:/BASE_DIR"}}' > .\bin\Release\net11.0\startup.json

# Run from current directory
.\jellyfin.exe

# Result: Uses E:/CURRENT_DIR (current directory checked first)
```

---

## Summary

### ✅ YES - startup.json IS Checked on Startup!

**When:** During application initialization in `CreateApplicationPaths()`

**Where:** Searches 3 locations (current dir, base dir, config subdir)

**Priority:** 3rd in the resolution chain:
1. Command-line args (highest)
2. Environment variables
3. **startup.json** ← HERE
4. Built-in defaults (lowest)

**What's Read:** All `Paths:*` values:
- `Paths:DataDir`
- `Paths:ConfigDir`
- `Paths:CacheDir`
- `Paths:LogDir`
- `Paths:TempDir`
- `Paths:WebDir`

**Confirmation:** Console output shows "Loaded startup configuration from: [path]" when found

---

## Code References

| Function | File | Purpose |
|----------|------|---------|
| `StartApp()` | Program.cs:88 | Entry point |
| `CreateApplicationPaths()` | StartupHelpers.cs:222 | Path resolution |
| `LoadStartupConfiguration()` | StartupHelpers.cs:78 | Loads startup.json |
| `CreateDefaultStartupConfiguration()` | StartupHelpers.cs:116 | Creates default if missing |

---

**Verified:** The code absolutely checks and uses startup.json on every startup! ✅
