Use Keys for Consistent Answers
How to use keys for consistent answers across questions and templates
How to Use Keys
Keys control answer reuse across questions and templates. Understanding keys is essential for creating composable templates.
How Keys Work
Every question has an id parameter that serves as its key:
const name = await i.text('Project name?', 'project.name', 'Enter name');
name = i.text('Project name?', 'project.name', 'Enter name')
var name = await i.Text("Project name?", "project.name", "Enter name");
Same Key = Same Answer
If multiple questions share the same key, they receive the same answer:
// First question - user enters "my-project"const name1 = await i.text('Project name?', 'project.name', 'Enter name');// Second question with same key - automatically gets "my-project"const name2 = await i.text('Confirm name?', 'project.name', '...');console.log(name1 === name2); // true
# First question - user enters "my-project"name1 = i.text('Project name?', 'project.name', 'Enter name')# Second question with same key - automatically gets "my-project"name2 = i.text('Confirm name?', 'project.name', '...')print(name1 == name2) # True
// First question - user enters "my-project"var name1 = await i.Text("Project name?", "project.name", "Enter name");// Second question with same key - automatically gets "my-project"var name2 = await i.Text("Confirm name?", "project.name", "...");Console.WriteLine(name1 == name2); // true
The user is only prompted once for each unique key. Subsequent questions with the same key receive the cached answer.
Namespacing Your Keys
Prevent collisions with other templates by namespacing:
// Good: namespaced keysconst name = await i.text('Name?', 'my-template.project.name', '...');const version = await i.text('Version?', 'my-template.project.version', '...');// Bad: generic keys that might collideconst name = await i.text('Name?', 'name', '...');const version = await i.text('Version?', 'version', '...');
# Good: namespaced keysname = i.text('Name?', 'my-template.project.name', '...')version = i.text('Version?', 'my-template.project.version', '...')# Bad: generic keys that might collidename = i.text('Name?', 'name', '...')version = i.text('Version?', 'version', '...')
// Good: namespaced keysvar name = await i.Text("Name?", "my-template.project.name", "...");var version = await i.Text("Version?", "my-template.project.version", "...");// Bad: generic keys that might collidevar name = await i.Text("Name?", "name", "...");var version = await i.Text("Version?", "version", "...");
Why Namespacing Matters
When templates are composed, non-namespaced keys cause conflicts:
With namespacing:
Cross-Template Keys
Keys persist across template composition. Use this intentionally:
Intentional Sharing
Share answers between templates when desired:
// Template A - sets the project nameconst name = await i.text('Project name?', 'global.project.name', '...');// Template B - uses the same name without asking againconst name = await i.text('Project name?', 'global.project.name', '...');
# Template A - sets the project namename = i.text('Project name?', 'global.project.name', '...')# Template B - uses the same name without asking againname = i.text('Project name?', 'global.project.name', '...')
// Template A - sets the project namevar name = await i.Text("Project name?", "global.project.name", "...");// Template B - uses the same name without asking againvar name = await i.Text("Project name?", "global.project.name", "...");
Avoiding Collisions
Use unique prefixes to avoid accidental sharing:
// Database templateconst dbName = await i.text('Database name?', 'db-template.database.name', '...');// API template - won't get db-template's answerconst apiName = await i.text('API name?', 'api-template.api.name', '...');
# Database templatedb_name = i.text('Database name?', 'db-template.database.name', '...')# API template - won't get db-template's answerapi_name = i.text('API name?', 'api-template.api.name', '...')
// Database templatevar dbName = await i.Text("Database name?", "db-template.database.name", "...");// API template - won't get db-template's answervar apiName = await i.Text("API name?", "api-template.api.name", "...");
Key Naming Convention
Follow a consistent naming pattern:
// Pattern: {template-name}.{category}.{field}// Template-specificconst name = await i.text('Name?', 'node-template.project.name', '...');const version = await i.text('Version?', 'node-template.project.version', '...');// Category-specific (shared within template)const dbHost = await i.text('Host?', 'node-template.database.host', '...');const dbPort = await i.text('Port?', 'node-template.database.port', '...');// Global (shared across templates)const orgName = await i.text('Organization?', 'global.organization.name', '...');
# Pattern: {template-name}.{category}.{field}# Template-specificname = i.text('Name?', 'node-template.project.name', '...')version = i.text('Version?', 'node-template.project.version', '...')# Category-specific (shared within template)db_host = i.text('Host?', 'node-template.database.host', '...')db_port = i.text('Port?', 'node-template.database.port', '...')# Global (shared across templates)org_name = i.text('Organization?', 'global.organization.name', '...')
// Pattern: {template-name}.{category}.{field}// Template-specificvar name = await i.Text("Name?", "node-template.project.name", "...");var version = await i.Text("Version?", "node-template.project.version", "...");// Category-specific (shared within template)var dbHost = await i.Text("Host?", "node-template.database.host", "...");var dbPort = await i.Text("Port?", "node-template.database.port", "...");// Global (shared across templates)var orgName = await i.Text("Organization?", "global.organization.name", "...");
Common Patterns
Confirming Values
// Ask onceconst email = await i.text('Email?', 'user.email', 'Your email');// Confirm without re-promptingconst confirmEmail = await i.confirm(`Use ${email} for notifications?`,'user.email','Confirm email');
# Ask onceemail = i.text('Email?', 'user.email', 'Your email')# Confirm without re-promptingconfirm_email = i.confirm(f'Use {email} for notifications?','user.email','Confirm email')
// Ask oncevar email = await i.Text("Email?", "user.email", "Your email");// Confirm without re-promptingvar confirmEmail = await i.Confirm($"Use {email} for notifications?","user.email","Confirm email");
Step-by-Step Collection
// Collect in stages, referencing earlier answersconst projectName = await i.text('Project name?', 'project.name', '...');const componentName = await i.text('Main component name?','project.name','Defaults to project name');
# Collect in stages, referencing earlier answersproject_name = i.text('Project name?', 'project.name', '...')component_name = i.text('Main component name?','project.name','Defaults to project name')
// Collect in stages, referencing earlier answersvar projectName = await i.Text("Project name?", "project.name", "...");var componentName = await i.Text("Main component name?","project.name","Defaults to project name");
Best Practices
- Always namespace - Prevent collisions in composed templates
- Be consistent - Use a predictable naming pattern
- Document shared keys - If intentionally sharing, document it
- Test composition - Verify your template works when composed
Related
- IInquirer Reference - Complete API documentation
- Compose Templates - Combining templates
- Tutorials: Asking Questions - Keys concept introduction