diff --git a/frontend/src/components/LinkedAppsSection.jsx b/frontend/src/components/LinkedAppsSection.jsx
new file mode 100644
index 00000000..77f47272
--- /dev/null
+++ b/frontend/src/components/LinkedAppsSection.jsx
@@ -0,0 +1,151 @@
+import React from 'react';
+import { GitBranch, Link2, Unlink, ExternalLink, Server } from 'lucide-react';
+
+const LinkedAppsSection = ({
+ app,
+ linkedApps,
+ onLink,
+ onUnlink,
+ onNavigate,
+ loading
+}) => {
+ const envLabels = {
+ production: 'Production',
+ development: 'Development',
+ staging: 'Staging',
+ standalone: 'Standalone'
+ };
+
+ const envColors = {
+ production: 'env-production',
+ development: 'env-development',
+ staging: 'env-staging'
+ };
+
+ const getStatusClass = (status) => {
+ switch (status) {
+ case 'running': return 'status-active';
+ case 'stopped': return 'status-stopped';
+ case 'error': return 'status-error';
+ default: return 'status-warning';
+ }
+ };
+
+ return (
+
+
+
+
+ Environment Linking
+
+ {!app.has_linked_app && (
+
+ )}
+
+
+
+ {/* Current app environment */}
+
+ This app is:
+
+ {envLabels[app.environment_type] || 'Standalone'}
+
+
+
+ {/* Linked apps list */}
+ {linkedApps && linkedApps.length > 0 ? (
+
+
+ Linked to
+
+ {linkedApps.map(linkedApp => (
+
+
+
+
+
+
+
{linkedApp.name}
+
+
+ {envLabels[linkedApp.environment_type] || linkedApp.environment_type}
+
+
+
+ {linkedApp.status}
+
+ {linkedApp.port && (
+ :{linkedApp.port}
+ )}
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : app.environment_type !== 'standalone' ? (
+
+
No linked apps. Link another app to share database resources.
+
+
+ ) : (
+
+
+ Link this app to another to create a production/development pair.
+ Linked apps can share database credentials with different table prefixes.
+
+
+ )}
+
+ {/* Shared config info */}
+ {app.shared_config && app.shared_config.db_credentials_propagated && (
+
+
+
+ Shared Database
+
+ {app.shared_config.shared_db && (
+
+ Host: {app.shared_config.shared_db.db_host}
+ Table prefix: {app.shared_config.shared_db.target_prefix || app.shared_config.shared_db.source_prefix}
+
+ )}
+
+ )}
+
+
+ );
+};
+
+export default LinkedAppsSection;
diff --git a/frontend/src/styles/components/_linked-apps.less b/frontend/src/styles/components/_linked-apps.less
new file mode 100644
index 00000000..2cdb82be
--- /dev/null
+++ b/frontend/src/styles/components/_linked-apps.less
@@ -0,0 +1,220 @@
+// ============================================
+// LINKED APPS SECTION
+// ============================================
+
+.linked-apps-section {
+ margin-top: @space-4;
+}
+
+.linked-apps-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: @space-4;
+
+ h3 {
+ display: flex;
+ align-items: center;
+ gap: @space-2;
+ margin: 0;
+ font-size: @font-size-base;
+ font-weight: @font-weight-semibold;
+ color: @text-primary;
+ }
+}
+
+.linked-apps-content {
+ display: flex;
+ flex-direction: column;
+ gap: @space-4;
+}
+
+.current-environment {
+ display: flex;
+ align-items: center;
+ gap: @space-3;
+ padding: @space-3;
+ background: @bg-hover;
+ border-radius: @radius-md;
+
+ .env-label {
+ font-size: @font-size-sm;
+ color: @text-secondary;
+ }
+}
+
+.linked-apps-divider {
+ display: flex;
+ align-items: center;
+ gap: @space-3;
+ color: @text-tertiary;
+ font-size: @font-size-sm;
+
+ &::before,
+ &::after {
+ content: '';
+ flex: 1;
+ height: 1px;
+ background: @border-subtle;
+ }
+}
+
+.linked-apps-list {
+ display: flex;
+ flex-direction: column;
+ gap: @space-3;
+}
+
+.linked-app-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: @space-3;
+ background: @bg-card;
+ border: 1px solid @border-subtle;
+ border-radius: @radius-md;
+ transition: border-color @transition-fast;
+
+ &:hover {
+ border-color: @border-default;
+ }
+}
+
+.linked-app-info {
+ display: flex;
+ align-items: center;
+ gap: @space-3;
+}
+
+.linked-app-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 36px;
+ height: 36px;
+ background: @accent-glow;
+ color: @accent-primary;
+ border-radius: @radius-md;
+}
+
+.linked-app-details {
+ display: flex;
+ flex-direction: column;
+ gap: @space-1;
+}
+
+.linked-app-name {
+ font-weight: @font-weight-medium;
+ color: @text-primary;
+}
+
+.linked-app-meta {
+ display: flex;
+ align-items: center;
+ gap: @space-2;
+ font-size: @font-size-sm;
+}
+
+.linked-app-port {
+ color: @text-tertiary;
+ font-family: @font-family-mono;
+ font-size: @font-size-xs;
+}
+
+.linked-app-actions {
+ display: flex;
+ gap: @space-2;
+}
+
+.linked-apps-empty,
+.linked-apps-info {
+ padding: @space-4;
+ text-align: center;
+ background: @bg-hover;
+ border-radius: @radius-md;
+
+ p {
+ margin: 0 0 @space-3;
+ color: @text-secondary;
+ font-size: @font-size-sm;
+ }
+
+ .btn {
+ margin-top: @space-2;
+ }
+}
+
+.linked-apps-info p {
+ margin: 0;
+}
+
+// Shared config info
+.shared-config-info {
+ padding: @space-3;
+ background: fade(@accent-primary, 10%);
+ border: 1px solid fade(@accent-primary, 20%);
+ border-radius: @radius-md;
+}
+
+.shared-config-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: @space-1;
+ font-size: @font-size-sm;
+ font-weight: @font-weight-medium;
+ color: @accent-primary;
+ margin-bottom: @space-2;
+}
+
+.shared-config-details {
+ display: flex;
+ flex-wrap: wrap;
+ gap: @space-3;
+ font-size: @font-size-xs;
+ color: @text-secondary;
+ font-family: @font-family-mono;
+
+ span {
+ background: @bg-card;
+ padding: @space-1 @space-2;
+ border-radius: @radius-sm;
+ }
+}
+
+// Small status badge variant
+.status-badge-sm {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 2px 8px;
+ border-radius: @radius-full;
+ font-size: @font-size-xs;
+ font-weight: @font-weight-medium;
+
+ .status-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: currentColor;
+ }
+
+ &.status-active {
+ background: @success-bg;
+ color: @success;
+ }
+
+ &.status-stopped {
+ background: fade(@text-tertiary, 10%);
+ color: @text-tertiary;
+ }
+
+ &.status-error {
+ background: @danger-bg;
+ color: @danger;
+ }
+
+ &.status-warning {
+ background: @warning-bg;
+ color: @warning;
+ }
+}
diff --git a/frontend/src/styles/main.less b/frontend/src/styles/main.less
index e3f19435..12bd9c7c 100644
--- a/frontend/src/styles/main.less
+++ b/frontend/src/styles/main.less
@@ -49,6 +49,7 @@
@import 'components/_deploy';
@import 'components/_build';
@import 'components/_users';
+@import 'components/_linked-apps';
// --------------------------------------------
// 5. PAGE-SPECIFIC STYLES