Intents, Slots & Slot Types
Designing structured conversation flows via SDK.
Search across all documentation pages
Designing structured conversation flows via SDK.
An intent's sample utterances get you matched to the right user goal; slots and slot types are what let that intent collect the specific values it needs to act. This page covers defining a custom slot type as an enumeration, attaching a slot of that type to an intent, and the elicitation prompt Lex uses to ask for it - the full conversation-design layer that sits between recognizing an intent and fulfilling it.
Quick-reference recipe card - copy-paste ready.
# --- Python (boto3) ---
slot_type = lex_models.create_slot_type(
botId=bot_id, botVersion="DRAFT", localeId="en_US",
slotTypeName="PizzaSize",
slotTypeValues=[
{"sampleValue": {"value": "small"}},
{"sampleValue": {"value": "medium"}},
{"sampleValue": {"value": "large"}, "synonyms": [{"value": "big"}]},
],
valueSelectionSetting={"resolutionStrategy": "TopResolution"},
)
# Then create_slot(...) attaches slot_type["slotTypeId"] to an intent.// --- TypeScript (AWS SDK v3) ---
const slotType = await lexModels.send(new CreateSlotTypeCommand({
botId: botId, botVersion: "DRAFT", localeId: "en_US",
slotTypeName: "PizzaSize",
slotTypeValues: [
{ sampleValue: { value: "small" } },
{ sampleValue: { value: "medium" } },
{ sampleValue: { value: "large" }, synonyms: [{ value: "big" }] },
],
valueSelectionSetting: { resolutionStrategy: "TopResolution" },
}));
// Then CreateSlotCommand attaches slotType.slotTypeId to an intent.When to reach for this:
"big" -> large) normalized to one canonical value before your fulfillment logic sees it.AMAZON.Date, AMAZON.Number, AMAZON.City, AMAZON.PhoneNumber, and others).Define a custom slot type, attach a required slot of that type to an intent, and give the intent a sample utterance that references the slot by name.
# --- Python (boto3) ---
import boto3
lex_models = boto3.client("lexv2-models", region_name="us-east-1")
# 1. Custom slot type - an enumeration with synonyms.
slot_type = lex_models.create_slot_type(
botId=bot_id, botVersion="DRAFT", localeId="en_US",
slotTypeName="PizzaSize",
description="Available pizza sizes.",
slotTypeValues=[
{"sampleValue": {"value": "small"}},
{"sampleValue": {"value": "medium"}},
{"sampleValue": {"value": "large"}, "synonyms": [{"value": "big"}, {"value": "family size"}]},
],
valueSelectionSetting={"resolutionStrategy": "TopResolution"}, # normalize to the canonical value
)
# 2. Intent whose utterance references the slot by name in curly braces.
intent = lex_models.create_intent(
botId=bot_id, botVersion="DRAFT", localeId="en_US",
intentName="OrderPizza",
sampleUtterances=[
{"utterance": "I'd like to order a pizza"},
{"utterance": "Can I get a {Size} pizza"},
],
)
# 3. Slot - attaches the slot type to the intent, with a prompt for when it's missing.
lex_models.create_slot(
botId=bot_id, botVersion="DRAFT", localeId="en_US",
intentId=intent["intentId"],
slotName="Size",
slotTypeId=slot_type["slotTypeId"],
valueElicitationSetting={
"slotConstraint": "Required",
"promptSpecification": {
"messageGroupsList": [
{"message": {"plainTextMessage": {"value": "What size would you like - small, medium, or large?"}}}
],
"maxRetries": 2,
},
},
)// --- TypeScript (AWS SDK v3) ---
import {
LexModelsV2Client, CreateSlotTypeCommand, CreateIntentCommand, CreateSlotCommand,
} from "@aws-sdk/client-lex-models-v2";
const lexModels = new LexModelsV2Client({ region: "us-east-1" });
// 1. Custom slot type - an enumeration with synonyms.
const slotType = await lexModels.send(new CreateSlotTypeCommand({
botId: botId, botVersion: "DRAFT", localeId: "en_US",
slotTypeName: "PizzaSize",
description: "Available pizza sizes.",
slotTypeValues: [
{ sampleValue: { value: "small" } },
{ sampleValue: { value: "medium" } },
{ sampleValue: { value: "large" }, synonyms: [{ value: "big" }, { value: "family size" }] },
],
valueSelectionSetting: { resolutionStrategy: "TopResolution" }, // normalize to the canonical value
}));
// 2. Intent whose utterance references the slot by name in curly braces.
const intent = await lexModels.send(new CreateIntentCommand({
botId: botId, botVersion: "DRAFT", localeId: "en_US",
intentName: "OrderPizza",
sampleUtterances: [
{ utterance: "I'd like to order a pizza" },
{ utterance: "Can I get a {Size} pizza" },
],
}));
// 3. Slot - attaches the slot type to the intent, with a prompt for when it's missing.
await lexModels.send(new CreateSlotCommand({
botId: botId, botVersion: "DRAFT", localeId: "en_US",
intentId: intent.intentId!,
slotName: "Size",
slotTypeId: slotType.slotTypeId!,
valueElicitationSetting: {
slotConstraint: "Required",
promptSpecification: {
messageGroupsList: [
{ message: { plainTextMessage: { value: "What size would you like - small, medium, or large?" } } },
],
maxRetries: 2,
},
},
}));What this demonstrates:
slotTypeValues is a list of sampleValue/synonyms pairs; valueSelectionSetting.resolutionStrategy decides what Lex reports back for a synonym match.{Size} placeholder in a sample utterance must exactly match the slotName you later create for that intent.valueElicitationSetting.slotConstraint: "Required" plus a promptSpecification is what makes Lex actively ask for a missing slot.CreateSlot can reference them.resolutionStrategy controls what value shows up in sessionState when the user's words don't exactly match a sampleValue:
OriginalValue - Lex passes through whatever the user said, unnormalized. Use this when you want the raw text (free-form-ish values you'll parse yourself).TopResolution - Lex maps a recognized synonym to its canonical sampleValue. Use this for anything you'll branch on in code - "big" and "family size" both resolve to "large".Concatenation - for multi-value slot behavior in specific configurations; less common than the first two.In the runtime response, the resolved value lives at slots.Size.value.interpretedValue (the resolved/normalized value) alongside value.originalValue (exactly what the user said) and value.resolvedValues (all candidate matches) - covered in full on the runtime handling page.
Lex ships a large catalog of built-in types - AMAZON.Date, AMAZON.Number, AMAZON.City, AMAZON.PhoneNumber, AMAZON.Airport, and more - that already handle common data shapes with locale-aware parsing. Reach for a custom slot type only when the values are specific to your domain (product names, internal tiers, plan codes) and not already covered.
valueElicitationSetting.slotConstraint is either Required or Optional. A Required slot needs a promptSpecification - the message(s) Lex uses to ask for it, plus maxRetries before giving up. An Optional slot is filled only if the user volunteers it in the same utterance; Lex never prompts for it on its own.
When an intent has multiple slots, slotPriorities (set on the intent) controls the order Lex elicits them in in the default dialog flow. For values that are naturally grouped (a full address, a date range), a composite slot type groups several sub-slots under one logical slot rather than eliciting each independently - useful once a single-value slot no longer fits the data.
{PlaceholderName} text must exactly match slotName, case-sensitive.BuildBotLocale again; changes only take effect after a successful build.slotConstraint: "Required" with a promptSpecification.OriginalValue gives you a clean enum - code branching on raw user text breaks on synonyms. Fix: use TopResolution when you need a normalized value to switch on.CreateSlot references IDs that must already exist. Fix: create the slot type and the intent first, then the slot.| Approach | Use When | Don't Use When |
|---|---|---|
Built-in slot type (AMAZON.Date, etc.) | The value shape is common and already covered | The values are domain-specific enumerations |
| Custom slot type (this page) | A small, known set of domain values with synonyms | The input is genuinely open-ended text |
| Composite slot type | Several related sub-values belong to one logical slot | A single value is enough |
No slot - free text via AMAZON.FreeFormInput or fulfillment parsing | You want to parse or hand off unstructured input yourself | You need Lex to validate and re-prompt automatically |
Wrap the slot name in curly braces, like "a {Size} pizza". The name inside the braces must exactly match the slotName you create for that intent.
OriginalValue returns exactly what the user said; TopResolution normalizes a synonym match to your canonical sampleValue. Use TopResolution when your code branches on the result.
Only for Required slots - Lex needs a promptSpecification to know what to ask. Optional slots are filled only if volunteered and are never actively elicited.
Whenever a built-in (AMAZON.Date, AMAZON.Number, AMAZON.City, and others) already matches the data shape you need - they include locale-aware parsing you would otherwise have to rebuild.
No. Changes apply to DRAFT and only take effect in a new version after you rebuild the locale and publish. Published versions are immutable snapshots.
slotPriorities on the intent. Lex elicits missing required slots in that priority order during the default dialog flow.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 24, 2026