--- title: 'Scoped Taskfiles' description: Experiment for variable isolation and env namespace in included Taskfiles outline: deep --- # Scoped Taskfiles ::: warning All experimental features are subject to breaking changes and/or removal _at any time_. We strongly recommend that you do not use these features in a production environment. They are intended for testing and feedback only. ::: ::: danger This experiment breaks the following functionality: - **Environment variables are no longer available at root level in templates** - Before: `{{.PATH}}`, `{{.MY_ENV}}` - After: `{{.env.PATH}}`, `{{.env.MY_ENV}}` - **Variables from sibling includes are no longer visible** - Include A cannot access variables defined in Include B - Each include only sees: root vars + its own vars + parent vars ::: ::: info To enable this experiment, set the environment variable: `TASK_X_SCOPED_TASKFILES=1`. Check out [our guide to enabling experiments](./index.md#enabling-experiments) for more information. ::: This experiment introduces two major changes to how variables work in Task: 1. **Environment namespace**: Environment variables (both OS and Taskfile `env:` sections) are moved to a dedicated `{{.env.XXX}}` namespace, separating them from regular variables 2. **Variable scoping**: Variables defined in included Taskfiles are isolated - sibling includes cannot see each other's variables ## Environment Namespace With this experiment enabled, environment variables are no longer mixed with regular variables at the template root level. Instead, they are accessible through the `{{.env.XXX}}` namespace. ### Comparison Table | Template | Legacy | SCOPED_TASKFILES | | ----------------------------------------------- | ------ | ------------------------- | | `{{.MY_VAR}}` (from `vars:`) | Works | Works | | `{{.MY_ENV}}` (from `env:`) | Works | `` | | `{{.env.MY_ENV}}` | - | Works | | `{{.PATH}}` (OS) | Works | `` | | `{{.env.PATH}}` (OS) | - | Works | | `{{.TASK}}` (special) | Works | Works (stays at root) | ### Example ```yaml version: '3' env: DB_HOST: localhost vars: DB_NAME: mydb tasks: show: cmds: # Access Taskfile env: section - echo "Host: {{.env.DB_HOST}}" # Access regular vars (unchanged) - echo "Name: {{.DB_NAME}}" # Access OS environment variables - echo "Path: {{.env.PATH}}" # Special variables stay at root level - echo "Task: {{.TASK}}" ``` ## Variable Scoping Variables defined in included Taskfiles are now isolated from each other. Sibling includes cannot access each other's variables, but child includes can still inherit variables from their parent. ### Example ```yaml # Taskfile.yml version: '3' vars: ROOT_VAR: from_root includes: api: ./api web: ./web ``` ```yaml # api/Taskfile.yml version: '3' vars: API_VAR: from_api tasks: show: cmds: # Inherited from root - works - echo "ROOT_VAR={{.ROOT_VAR}}" # Own variable - works - echo "API_VAR={{.API_VAR}}" # From sibling include - NOT visible - echo "WEB_VAR={{.WEB_VAR}}" ``` ```yaml # web/Taskfile.yml version: '3' vars: WEB_VAR: from_web tasks: show: cmds: # Inherited from root - works - echo "ROOT_VAR={{.ROOT_VAR}}" # Own variable - works - echo "WEB_VAR={{.WEB_VAR}}" # From sibling include - NOT visible - echo "API_VAR={{.API_VAR}}" ``` ## CLI Variables Priority With this experiment, CLI variables (passed as `task foo VAR=value`) have the highest priority and will override task-level variables. ```yaml version: '3' tasks: greet: vars: NAME: from_task cmds: - echo "Hello {{.NAME}}" ``` ```bash # CLI vars now override task vars TASK_X_SCOPED_TASKFILES=1 task greet NAME=cli # Output: Hello cli ``` ## Migration Guide To migrate your Taskfiles to use this experiment: 1. **Update environment variable references** in your templates: - `{{.PATH}}` becomes `{{.env.PATH}}` - `{{.HOME}}` becomes `{{.env.HOME}}` - `{{.MY_TASKFILE_ENV}}` becomes `{{.env.MY_TASKFILE_ENV}}` 2. **Variables in `vars:` sections remain unchanged**: - `{{.MY_VAR}}` still works the same way 3. **Special variables stay at root level**: - `{{.TASK}}`, `{{.ROOT_DIR}}`, `{{.TASKFILE}}`, `{{.TASKFILE_DIR}}`, etc. 4. **Review cross-include variable dependencies**: - If your included Taskfiles rely on variables from sibling includes, you'll need to either move those variables to the root Taskfile or pass them explicitly via the `vars:` attribute in the `includes:` section.