Understanding CRUD operations, import, and lifecycle management for Microsoft 365 resources in Terraform
This guide explains how Terraform manages Microsoft 365 resources throughout their lifecycle, including creation, reading, updating, deletion, and import operations.
When you run terraform apply with a new resource, Terraform creates it in Microsoft 365 using the Microsoft Graph API.
resource "microsoft365_graph_beta_groups_group" "engineering" { display_name = "Engineering Team" mail_nickname = "engineering-team" description = "Security group for engineering team members" security_enabled = true mail_enabled = false group_types = []}
Behind the scenes:
Provider constructs the Microsoft Graph API request body
Issues POST /groups to create the group
Waits for eventual consistency (typically 25 seconds)
Reads the resource back to populate state with all attributes
Stores the resource ID and all computed values in state
Many Microsoft 365 resources require eventual consistency delays after creation. The provider automatically handles these delays to ensure reliable state management.
Terraform reads resources during terraform plan and terraform refresh to detect configuration drift.When reads occur:
During terraform plan to detect changes
During terraform apply to verify current state
After create/update operations to refresh state
During terraform refresh for explicit state synchronization
Example read behavior:
resource "microsoft365_graph_beta_device_and_app_management_win32_app" "vscode" { display_name = "Visual Studio Code" # ... other configuration ...}
The provider issues GET /deviceAppManagement/mobileApps/{id} and compares the response with the configuration to detect drift.
Understanding API expansion
Many resources use $expand=* query parameters to retrieve related objects in a single API call. For example, application resources expand owners, while app configuration policies expand settings.This optimization reduces API calls and improves performance but may retrieve more data than strictly necessary.
Issues PATCH /groups/{id} with only changed attributes
Waits for eventual consistency if needed
Reads resource back to update state
Some attributes are immutable and cannot be changed after creation. Attempting to change these attributes forces resource replacement (destroy + recreate). Check the resource documentation for immutable attributes.
Common immutable attributes:
User Principal Names (for users)
Group types (cannot change security group to Microsoft 365 group)
# Find the group IDaz ad group show --group "Marketing Team" --query id -o tsv# Add resource block to configurationcat >> main.tf <<EOFresource "microsoft365_graph_beta_groups_group" "marketing" { # Will be populated from import}EOF# Import the groupterraform import microsoft365_graph_beta_groups_group.marketing \ 98765432-9876-9876-9876-987654321abc# View what needs to be configuredterraform plan# Update configuration to match statecat >> main.tf <<EOFresource "microsoft365_graph_beta_groups_group" "marketing" { display_name = "Marketing Team" mail_nickname = "marketing-team" description = "Marketing department group" security_enabled = true mail_enabled = false group_types = []}EOF# Verify no changes neededterraform plan
Import a conditional access policy
# Import the policyterraform import microsoft365_graph_beta_identity_and_access_conditional_access_policy.mfa_policy \ 11111111-2222-3333-4444-555555555555# Use terraform show to view imported stateterraform show# Add configuration matching the imported state
Import an Intune Win32 app
# Import the Win32 appterraform import microsoft365_graph_beta_device_and_app_management_win32_app.chrome \ aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee# Note: Content files cannot be imported - you must provide setup_file_path# in configuration for future updates
Default timeouts vary by resource type. Win32 apps and other resources with file uploads typically have longer default timeouts (180 seconds) to accommodate large files.
Be aware of eventual consistency delays in Microsoft 365:
# Provider handles this automatically, but be aware:# - New resources may take 15-30 seconds to become available# - Changes may not be immediately visible in all APIs# - The provider includes automatic retry logic with backoff