Currently, Fresh relies on "magic folders" (islands/ or (_islands)) to identify interactive components. While this works for small projects, it creates a "Thin/Fat" model dilemma for large-scale, domain-driven architectures (common in monorepos).
I am currently building a site with multiple sections/sub-sections. My desired structure is:
auth/
components/
islands/ <-- Hidden from Fresh unless nested in routes
services/
billing/
islands/ <-- Not automatically detected
To make this work currently, I have to either squeeze everything into a routes/sub-section/(_islands) folder (which causes over-bundling and performance hits) or move them to a global islands/ folder (which breaks domain encapsulation).
Suggested Solution
I would like the ability to explicitly define island entry points or search patterns within the fresh.config.ts or deno.json. This would allow the compiler to "find" islands regardless of where they live in the file tree.
Proposed Configuration
export default defineConfig({
plugins: [
fresh({
islands: [
"./islands/**/*.tsx",
"./sections/**/islands/*.tsx",
"./shared/ui/**/*.island.tsx"
],
}),
],
});
Alternative Solutions
- The (_islands) colocation: While helpful, it forces a specific folder name and deep nesting within the routes directory, making the project structure feel "messy" as it grows.
- Manual Manifesting: Manually editing the fresh.gen.ts, which is fragile and gets overwritten on every save.
Current
routes/
billing/
(_islands)/
PaymentForm.tsx <-- Must be here to work
CardIcon.tsx <-- Forced to be an island (Over-bundling!)
services/
billing_page.tsx
Proposed
features/
billing/
PaymentForm.island.tsx <-- Detected by glob
CardIcon.tsx <-- Remains static (Zero JS)
billing.service.ts
billing.contract.ts
Benfits
-
Enabling Domain-Driven Design (DDD)
Large-scale applications are rarely organized by "technical type" (putting all islands in one bucket). Instead, they are organized by "feature" (Auth, Billing, Dashboard). Current Fresh constraints force developers to break encapsulation by moving interactive logic far away from its related services and contracts. Explicit configuration allows the folder structure to follow the business logic, not the framework's limitations.
-
Solving the "Fat Island" Performance Bottleneck
Currently, placing a component in an islands/ or (_islands)/ folder is an "all-or-nothing" choice. If a component lives there, it is bundled for the client.
-
First-Class Monorepo Support
In a monorepo setup, interactive UI components often live in a shared workspace (e.g., packages/ui). Currently, importing these into Fresh requires complex workarounds because they aren't in the local islands/ directory. Allowing an array of paths makes shared component libraries "just work."
-
Reduced "Magic" and Increased Predictability
Relying on specific folder names like (_islands) is "magic" that can be confusing for new developers (especially those coming from Angular or React backgrounds). Moving this to a configuration file makes the application's boundaries explicit and easier to debug.
-
Parity with Modern Tooling
Since Fresh 2.0 is moving toward Vite, developers expect the flexibility that Vite provides. Almost every other modern framework (Astro, Vite-plugin-ssr, etc.) allows for custom entry-point discovery. Adding this keeps Fresh competitive with the ergonomics of the 2026 web ecosystem.
Currently, Fresh relies on "magic folders" (islands/ or (_islands)) to identify interactive components. While this works for small projects, it creates a "Thin/Fat" model dilemma for large-scale, domain-driven architectures (common in monorepos).
I am currently building a site with multiple sections/sub-sections. My desired structure is:
To make this work currently, I have to either squeeze everything into a routes/sub-section/(_islands) folder (which causes over-bundling and performance hits) or move them to a global islands/ folder (which breaks domain encapsulation).
Suggested Solution
I would like the ability to explicitly define island entry points or search patterns within the fresh.config.ts or deno.json. This would allow the compiler to "find" islands regardless of where they live in the file tree.
Proposed Configuration
Alternative Solutions
Current
Proposed
Benfits
Enabling Domain-Driven Design (DDD)
Large-scale applications are rarely organized by "technical type" (putting all islands in one bucket). Instead, they are organized by "feature" (Auth, Billing, Dashboard). Current Fresh constraints force developers to break encapsulation by moving interactive logic far away from its related services and contracts. Explicit configuration allows the folder structure to follow the business logic, not the framework's limitations.
Solving the "Fat Island" Performance Bottleneck
Currently, placing a component in an islands/ or (_islands)/ folder is an "all-or-nothing" choice. If a component lives there, it is bundled for the client.
First-Class Monorepo Support
In a monorepo setup, interactive UI components often live in a shared workspace (e.g., packages/ui). Currently, importing these into Fresh requires complex workarounds because they aren't in the local islands/ directory. Allowing an array of paths makes shared component libraries "just work."
Reduced "Magic" and Increased Predictability
Relying on specific folder names like (_islands) is "magic" that can be confusing for new developers (especially those coming from Angular or React backgrounds). Moving this to a configuration file makes the application's boundaries explicit and easier to debug.
Parity with Modern Tooling
Since Fresh 2.0 is moving toward Vite, developers expect the flexibility that Vite provides. Almost every other modern framework (Astro, Vite-plugin-ssr, etc.) allows for custom entry-point discovery. Adding this keeps Fresh competitive with the ergonomics of the 2026 web ecosystem.