A Drupal recipe for Thunder that installs and configures AI providers.
| Module | Description |
|---|---|
| drupal/ai | Core AI integration layer |
| drupal/ai_provider_azure | Azure OpenAI provider integration |
| drupal/ai_provider_openai | OpenAI provider integration |
| drupal/gemini_provider | Google Gemini provider integration |
| drupal/ai_provider_anthropic | Anthropic provider integration |
Apply the recipe using Drupal's recipe system:
drush recipe ../recipes/thunder_ai
The recipe asks the following questions:
azure, openai, gemini, or anthropicconfig (value stored in Drupal config) or env (value read from an environment variable)thunder_ai_azure (the Azure model registered by this recipe). Override when using a different provider (e.g. gpt-4o, claude-opus-4-5, gemini-2.0-flash)For questions 3, 5, 6, and 7: enter the raw API key when using config storage, or the environment variable name (e.g. OPENAI_API_KEY) when using env storage.
Note: Drupal recipe inputs cannot be made conditional, so all questions are always shown. Only fill in credentials and a model for the provider you selected; press Enter to skip the rest.
To skip the prompts entirely, pass all values as flags:
drush recipe ../recipes/thunder_ai \
--input="thunder_ai.default_provider=azure" \
--input="thunder_ai.default_model=thunder_ai_azure" \
--input="thunder_ai.key_provider=env" \
--input="thunder_ai.azure_api_key=AZURE_API_KEY" \
--input="thunder_ai.azure_endpoint=https://my-resource.openai.azure.com/openai/deployments/my-deployment/chat" \
--input="thunder_ai.openai_api_key=" \
--input="thunder_ai.gemini_api_key=" \
--input="thunder_ai.anthropic_api_key="
All four provider modules are installed regardless of the selection. The chosen provider is set as the site default for chat operations.
For each provider whose credentials are supplied, the recipe:
thunder_ai_{provider}_key) using the chosen key provider (config or env)ai.settings.models with the given endpointai.settingsNon-Azure model — ai.settings.default_providers.chat.model_id is set from the default_model input. If you selected OpenAI, Gemini, or Anthropic, visit Administration > Configuration > AI to update the default model.
Production key storage — credentials are stored in Drupal config via the Key module's config provider. For production environments, switch to an environment-variable-based key provider at Administration > Configuration > System > Keys.
Drupal recipes have no conditional logic — it is not possible to install a module only when a specific input value is chosen. All four provider modules are always installed regardless of the selection. The chosen provider is set as the site default; the others are installed but unconfigured. See Removing unneeded providers below for how to clean them up.
thunder_ai_azure when I selected a different provider?Azure OpenAI requires an explicit model registration in ai.settings.models that includes the deployment endpoint URL. The recipe registers one such model (thunder_ai_azure) using the endpoint supplied as input. Other providers discover available models dynamically and need no registration entry. Because the recipe always creates the Azure model entry, the default_model input defaults to thunder_ai_azure. When using a different provider, override the default_model input during recipe application or update the default model afterwards at Administration > Configuration > AI.
setupAiProvider not used to configure the providers?The drupal/ai module provides a setupAiProvider config action that creates a Key entity and wires it to a provider in one step. It was not used for two reasons:
getSetupData() — it returns an empty array — which causes the action to fail for Azure.setupAiProvider hardcodes the Key module's config storage backend. There is no way to have it create a Key entity that reads from an environment variable instead.The recipe uses createIfNotExists and simpleConfigUpdate directly, which avoids both limitations and works uniformly for all four providers.
The recipe installs all four AI provider modules. Once you have decided which provider to use, you can unpack the recipe and remove the providers you do not need.
Unpacking inlines the recipe's Composer dependencies into your project's composer.json and removes the recipe package itself, giving you full control over each dependency.
1. Install the unpack plugin
composer require drupal/core-recipe-unpack
2. Unpack the recipe
composer drupal:recipe-unpack drupal/thunder_ai
This moves all packages from drupal/thunder_ai's require into your root composer.json and removes the recipe package.
3. Uninstall the unused Drupal modules
Drupal modules must be uninstalled before their packages are removed from Composer. Removing the package first leaves Drupal with a reference to a missing module, which causes pm:uninstall to fail.
drush pm:uninstall ai_provider_azure # not using Azure OpenAI
drush pm:uninstall ai_provider_openai # not using OpenAI
drush pm:uninstall gemini_provider # not using Google Gemini
drush pm:uninstall ai_provider_anthropic # not using Anthropic
4. Delete the unused Key config entries
drush config:delete key.key.thunder_ai_azure_key
drush config:delete key.key.thunder_ai_openai_key
drush config:delete key.key.thunder_ai_gemini_key
drush config:delete key.key.thunder_ai_anthropic_key
5. Export the updated configuration
drush config:export
6. Remove the unused provider packages
Now that the modules are uninstalled, remove their Composer packages:
composer remove drupal/ai_provider_azure
composer remove drupal/ai_provider_openai
composer remove drupal/gemini_provider
composer remove drupal/ai_provider_anthropic