Dataverse for Teams: Building Data-Driven Apps Inside Microsoft Teams
Dataverse for Teams brings the power of a relational database directly into Microsoft Teams. Teams users can now build sophisticated data-driven applications without leaving their collaboration environment.
What is Dataverse for Teams?
Dataverse for Teams is a built-in, low-code data platform that comes with every Teams environment. It provides:
- Relational data storage with business logic
- Built-in security and compliance
- Integration with Power Apps and Power Automate
- No additional licensing for Teams users
Creating Your First Table
In Teams, go to Power Apps tab and create a table:
// Table definition (conceptual - done through UI)
{
"name": "Project",
"displayName": "Projects",
"columns": [
{ "name": "Name", "type": "text", "required": true },
{ "name": "Status", "type": "choice", "options": ["Not Started", "In Progress", "Completed"] },
{ "name": "DueDate", "type": "dateOnly" },
{ "name": "Budget", "type": "currency" },
{ "name": "Owner", "type": "lookup", "relatedTable": "User" }
]
}
Building a Project Tracker App
Create a canvas app connected to your Dataverse table:
// App OnStart
Set(CurrentUser, User());
ClearCollect(
MyProjects,
Filter(
Projects,
Owner.Email = CurrentUser.Email
)
);
// Gallery displaying projects
Sort(
Filter(
Projects,
Status.Value <> "Completed" && DueDate <= Today() + 7
),
DueDate,
Ascending
)
// Form for creating new projects
SubmitForm(ProjectForm);
Notify("Project created successfully!", NotificationType.Success);
Navigate(HomeScreen, ScreenTransition.None);
Status indicator with conditional formatting:
// Status color based on due date
Switch(
true,
ThisItem.Status.Value = "Completed", Color.Green,
ThisItem.DueDate < Today(), Color.Red,
ThisItem.DueDate < Today() + 3, Color.Orange,
Color.Blue
)
// Days remaining calculation
If(
ThisItem.Status.Value = "Completed",
"Done",
Text(
DateDiff(Today(), ThisItem.DueDate, Days),
"[$-en-US]0"
) & " days left"
)
Creating Relationships
Define relationships between tables:
// Task table with relationship to Project
{
"name": "Task",
"columns": [
{ "name": "Title", "type": "text" },
{ "name": "Project", "type": "lookup", "relatedTable": "Projects" },
{ "name": "AssignedTo", "type": "lookup", "relatedTable": "User" },
{ "name": "Completed", "type": "boolean" }
]
}
// Displaying related tasks in project detail
Filter(
Tasks,
Project.Name = SelectedProject.Name
)
// Count of incomplete tasks
CountRows(
Filter(
Tasks,
Project.Name = ThisItem.Name && !Completed
)
)
Power Automate Integration
Create flows that respond to data changes:
# Flow definition (conceptual)
trigger:
type: dataverse
table: Projects
event: create
actions:
- type: teams
action: postMessage
channel: General
message: |
New project created: @{triggerBody()?['name']}
Owner: @{triggerBody()?['owner/fullname']}
Due: @{formatDateTime(triggerBody()?['duedate'], 'MMMM dd, yyyy')}
- type: outlook
action: sendEmail
to: "@{triggerBody()?['owner/emailaddress']}"
subject: "You've been assigned a new project"
body: |
Hi @{triggerBody()?['owner/firstname']},
You've been assigned to the project "@{triggerBody()?['name']}".
Due Date: @{formatDateTime(triggerBody()?['duedate'], 'MMMM dd, yyyy')}
Budget: @{triggerBody()?['budget']}
Access your projects in Teams.
Automated task assignment flow:
trigger:
type: dataverse
table: Tasks
event: update
condition: "@equals(triggerBody()?['completed'], true)"
actions:
- type: dataverse
action: listRecords
table: Tasks
filter: "project/id eq '@{triggerBody()?['project/id']}' and completed eq false"
outputVariable: remainingTasks
- type: condition
expression: "@equals(length(outputs('remainingTasks')?['body/value']), 0)"
true:
- type: dataverse
action: updateRecord
table: Projects
id: "@{triggerBody()?['project/id']}"
data:
status: "Completed"
- type: teams
action: postMessage
message: "Project @{triggerBody()?['project/name']} completed!"
Business Rules
Implement validation and automation with business rules:
// Validation rule: Budget must be positive
If(
ThisItem.Budget <= 0,
Notify("Budget must be greater than zero", NotificationType.Error);
false,
true
)
// Auto-set status based on dates
If(
ThisItem.DueDate < Today() && ThisItem.Status.Value <> "Completed",
Patch(
Projects,
ThisItem,
{ Status: { Value: "Overdue" } }
)
)
// Calculated column: Project health score
With(
{
taskCompletion: CountRows(Filter(Tasks, Project.Name = ThisItem.Name && Completed)) /
Max(CountRows(Filter(Tasks, Project.Name = ThisItem.Name)), 1),
budgetHealth: If(ThisItem.Spent <= ThisItem.Budget, 1, 0.5),
timeHealth: If(Today() <= ThisItem.DueDate, 1, 0.7)
},
Round((taskCompletion + budgetHealth + timeHealth) / 3 * 100, 0)
)
Security and Permissions
Dataverse for Teams inherits Teams security:
// Check user permissions
Set(
IsOwner,
LookUp(Projects, Name = SelectedProject.Name).Owner.Email = User().Email
);
Set(
IsTeamOwner,
// Team owners have elevated permissions
User().Email in TeamOwners
);
// Conditional UI based on permissions
If(
IsOwner || IsTeamOwner,
DisplayMode.Edit,
DisplayMode.View
)
// Filter data based on user role
If(
IsTeamOwner,
Projects,
Filter(Projects, Owner.Email = User().Email)
)
Migrating to Full Dataverse
When you outgrow Teams, upgrade to full Dataverse:
# Export solution from Dataverse for Teams
$teamEnvId = "your-teams-environment-id"
$solution = Get-AdminPowerAppEnvironmentSolutionPackages `
-EnvironmentName $teamEnvId `
-SolutionName "ProjectTracker"
Export-AdminPowerAppEnvironmentSolutionPackage `
-EnvironmentName $teamEnvId `
-SolutionName "ProjectTracker" `
-SolutionPath ".\ProjectTracker.zip"
# Import to full Dataverse environment
$prodEnvId = "your-production-environment-id"
Import-AdminPowerAppEnvironmentSolutionPackage `
-EnvironmentName $prodEnvId `
-SolutionPath ".\ProjectTracker.zip"
Best Practices
- Design for Teams context: Users interact in Teams, so keep the experience native
- Use relationships wisely: Normalize data but don’t over-engineer
- Leverage Team membership: Use existing Teams security model
- Plan for growth: Design tables that can migrate to full Dataverse
// Pattern: Centralized configuration
// Create a Settings table for app configuration
LookUp(Settings, Key = "MaxProjectsPerUser").Value
// Pattern: Audit trail
// Add CreatedBy, CreatedOn, ModifiedBy, ModifiedOn to all tables
Patch(
Projects,
ThisItem,
{
ModifiedBy: User(),
ModifiedOn: Now()
}
)
// Pattern: Soft delete instead of hard delete
Patch(
Projects,
ThisItem,
{
IsDeleted: true,
DeletedBy: User(),
DeletedOn: Now()
}
)
Dataverse for Teams democratizes data platform capabilities. Teams users can now build real applications with proper data management without needing IT involvement for simple use cases.