diff --git a/src/components/navigation-header/components/product-page-content/utils/get-nav-items.ts b/src/components/navigation-header/components/product-page-content/utils/get-nav-items.ts
index 198bb78f6e..114862afe2 100644
--- a/src/components/navigation-header/components/product-page-content/utils/get-nav-items.ts
+++ b/src/components/navigation-header/components/product-page-content/utils/get-nav-items.ts
@@ -146,6 +146,13 @@ export function getNavItems(currentProduct: ProductData): NavItem[] {
 		}
 	}
 
+	if (currentProduct.playgroundConfig?.labs?.length) {
+		items.push({
+			label: 'Playground',
+			url: `/${currentProduct.slug}/playground`,
+		})
+	}
+
 	/**
 	 * For Terraform, add a "Registry" item
 	 */
diff --git a/src/contexts/instruqt-lab/index.tsx b/src/contexts/instruqt-lab/index.tsx
index 8914b28692..b2186eed93 100644
--- a/src/contexts/instruqt-lab/index.tsx
+++ b/src/contexts/instruqt-lab/index.tsx
@@ -23,6 +23,8 @@ interface InstruqtContextProps {
 interface InstruqtProviderProps {
 	labId: string
 	children: ReactNode
+	defaultActive?: boolean
+	isPlayground?: boolean
 }
 
 const InstruqtContext = createContext<Partial<InstruqtContextProps>>({})
@@ -34,23 +36,31 @@ export const useInstruqtEmbed = (): Partial<InstruqtContextProps> =>
 export default function InstruqtProvider({
 	labId,
 	children,
+	defaultActive = false,
+	isPlayground = false,
 }: InstruqtProviderProps): JSX.Element {
-	const [active, setActive] = useState(false)
+	const [active, setActive] = useState(defaultActive)
 
 	return (
 		<InstruqtContext.Provider value={{ labId, active, setActive }}>
-			{children}
-			{active && (
-				<div id="instruqt-panel-target">
-					<Resizable
-						initialHeight={640}
-						panelActive={active}
-						setPanelActive={setActive}
-						style={{ top: '-28px' }}
-					>
-						<EmbedElement />
-					</Resizable>
-				</div>
+			{isPlayground ? (
+				children
+			) : (
+				<>
+					{children}
+					{active && (
+						<div id="instruqt-panel-target">
+							<Resizable
+								initialHeight={640}
+								panelActive={active}
+								setPanelActive={setActive}
+								style={{ top: '-28px' }}
+							>
+								<EmbedElement />
+							</Resizable>
+						</div>
+					)}
+				</>
 			)}
 		</InstruqtContext.Provider>
 	)
diff --git a/src/data/nomad.json b/src/data/nomad.json
index b4ec3ec91b..76485a6711 100644
--- a/src/data/nomad.json
+++ b/src/data/nomad.json
@@ -102,5 +102,32 @@
 	],
 	"integrationsConfig": {
 		"description": "A curated collection of official, partner, and community Nomad Integrations."
+	},
+
+	"playgroundConfig": {
+		"description": "Learn how to manage your workloads with Nomad.",
+		"sidebarLinks": [
+			{
+				"title": "Install Nomad",
+				"href": "/nomad/install"
+			},
+			{
+				"title": "Get Started with Nomad",
+				"href": "/nomad/tutorials/get-started"
+			},
+			{
+				"title": "Nomad documentation",
+				"href": "/nomad/docs"
+			}
+		],
+		"labs": [
+			{
+				"id": "nomad-sandbox",
+				"name": "Nomad sandbox",
+				"instruqtId": "hashicorp-learn/tracks/nomad-sandbox?token=em_0wOuIAyyjAQllLkc",
+				"description": "A Nomad cluster with three server nodes and one client node, Consul installed and configured, and Access Control Lists (ACLs) enabled for both Nomad and Consul.",
+				"products": ["nomad", "consul"]
+			}
+		]
 	}
 }
diff --git a/src/data/playground-config.json b/src/data/playground-config.json
new file mode 100644
index 0000000000..90a660ebda
--- /dev/null
+++ b/src/data/playground-config.json
@@ -0,0 +1,23 @@
+{
+	"terraform": {
+		"labId": "hashicorp-learn/tracks/terraform-build-your-first-configuration"
+	},
+	"vault": {
+		"labId": "hashicorp-learn/tracks/vault-basics"
+	},
+	"consul": {
+		"labId": "hashicorp-learn/tracks/consul-template-automate-reverse-proxy-config"
+	},
+	"nomad": {
+		"labId": "hashicorp-learn/tracks/nomad-basics"
+	},
+	"packer": {
+		"labId": "hashicorp-learn/tracks/packer-get-started-hcp"
+	},
+	"waypoint": {
+		"labId": "hashicorp-learn/tracks/waypoint-get-started-docker"
+	},
+	"boundary": {
+		"labId": "hashicorp-learn/tracks/boundary-basics"
+	}
+}
diff --git a/src/data/terraform.json b/src/data/terraform.json
index 1c6de4f9c6..9bc211a2f7 100644
--- a/src/data/terraform.json
+++ b/src/data/terraform.json
@@ -151,5 +151,38 @@
 			"path": "registry",
 			"productSlugForLoader": "terraform-docs-common"
 		}
-	]
+	],
+	"playgroundConfig": {
+		"description": "Learn how to create infrastructure with Terraform",
+		"sidebarLinks": [
+			{
+				"title": "Install Terraform",
+				"href": "/terraform/install"
+			},
+			{
+				"title": "Get Started with Terraform",
+				"href": "/terraform/tutorials/aws-get-started"
+			},
+			{
+				"title": "Terraform documentation",
+				"href": "/terraform/docs"
+			}
+		],
+		"labs": [
+			{
+				"id": "create-infrastructure",
+				"name": "Create Infrastructure",
+				"instruqtId": "hashicorp-learn/tracks/create-terraform-infrastructure?token=em__EA8k5ywxqiOejXd",
+				"description": "Learn how to create infrastructure with Terraform",
+				"products": ["terraform"]
+			},
+			{
+				"id": "vault-sandbox",
+				"name": "Vault Playground (test)",
+				"instruqtId": "hashicorp-learn/tracks/vault-sandbox?token=em_usmVkoZLWz8SAXNB",
+				"description": "Learn how to manage your secrets with Vault",
+				"products": ["vault"]
+			}
+		]
+	}
 }
diff --git a/src/data/vault.json b/src/data/vault.json
index e6bb0fe83c..4a4bd6190d 100644
--- a/src/data/vault.json
+++ b/src/data/vault.json
@@ -174,5 +174,37 @@
 				"href": "/vault/tutorials/custom-secrets-engine"
 			}
 		]
+	},
+	"playgroundConfig": {
+		"sidebarLinks": [
+			{
+				"title": "Install Vault",
+				"href": "/vault/install"
+			},
+			{
+				"title": "Get Started with Vault",
+				"href": "/vault/tutorials/get-started"
+			},
+			{
+				"title": "Vault Documentation",
+				"href": "/vault/docs"
+			}
+		],
+		"labs": [
+			{
+				"id": "vault-sandbox",
+				"name": "Vault Playground (test)",
+				"instruqtId": "hashicorp-learn/tracks/vault-sandbox?token=em_usmVkoZLWz8SAXNB",
+				"description": "Learn how to manage your secrets with Vault",
+				"products": ["vault"]
+			},
+			{
+				"id": "create-infrastructure",
+				"name": "Create Infrastructure",
+				"instruqtId": "hashicorp-learn/tracks/create-terraform-infrastructure?token=em__EA8k5ywxqiOejXd",
+				"description": "Learn how to create infrastructure with Terraform",
+				"products": ["terraform"]
+			}
+		]
 	}
 }
diff --git a/src/pages/[productSlug]/playground/[playgroundId].tsx b/src/pages/[productSlug]/playground/[playgroundId].tsx
new file mode 100644
index 0000000000..ae10e1b731
--- /dev/null
+++ b/src/pages/[productSlug]/playground/[playgroundId].tsx
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import { GetStaticPaths, GetStaticProps } from 'next'
+import { PRODUCT_DATA_MAP } from 'data/product-data-map'
+import SidebarSidecarLayout from 'layouts/sidebar-sidecar'
+import InstruqtProvider from 'contexts/instruqt-lab'
+import EmbedElement from 'components/lab-embed/embed-element'
+import {
+	generateTopLevelSidebarNavData,
+	generateProductLandingSidebarNavData,
+} from 'components/sidebar/helpers'
+
+interface PlaygroundPageProps {
+	product: (typeof PRODUCT_DATA_MAP)[keyof typeof PRODUCT_DATA_MAP]
+	playgroundId: string
+	playgroundName: string
+	playgroundDescription: string
+	layoutProps: {
+		breadcrumbLinks: { title: string; url: string }[]
+		navLevels: any[]
+	}
+}
+
+export default function PlaygroundView({
+	product,
+	playgroundId,
+	playgroundName,
+	playgroundDescription,
+	layoutProps,
+}: PlaygroundPageProps) {
+	return (
+		<SidebarSidecarLayout
+			breadcrumbLinks={layoutProps.breadcrumbLinks}
+			sidebarNavDataLevels={layoutProps.navLevels}
+		>
+			<div>
+				<h1 className="g-type-display-3">{playgroundName}</h1>
+				<p className="g-type-body" style={{ marginTop: '16px' }}>
+					{playgroundDescription}
+				</p>
+			</div>
+			<div style={{ height: '80vh', marginTop: '32px' }}>
+				<InstruqtProvider labId={playgroundId} defaultActive isPlayground>
+					<EmbedElement />
+				</InstruqtProvider>
+			</div>
+		</SidebarSidecarLayout>
+	)
+}
+
+export const getStaticPaths: GetStaticPaths = async () => {
+	const paths = []
+
+	// Generate paths for each product's playgrounds
+	Object.values(PRODUCT_DATA_MAP).forEach((product) => {
+		if (product.playgroundConfig?.labs) {
+			product.playgroundConfig.labs.forEach((playground) => {
+				paths.push({
+					params: {
+						productSlug: product.slug,
+						playgroundId: playground.id,
+					},
+				})
+			})
+		}
+	})
+
+	return {
+		paths,
+		fallback: false,
+	}
+}
+
+export const getStaticProps: GetStaticProps<PlaygroundPageProps> = async ({
+	params,
+}) => {
+	const productSlug = params?.productSlug as string
+	const playgroundId = params?.playgroundId as string
+	const product = PRODUCT_DATA_MAP[productSlug]
+
+	// Only show playground page if product has labs configured
+	if (!product || !product.playgroundConfig?.labs) {
+		return {
+			notFound: true,
+		}
+	}
+
+	const playground = product.playgroundConfig.labs.find(
+		(p) => p.id === playgroundId
+	)
+	if (!playground) {
+		return {
+			notFound: true,
+		}
+	}
+
+	const breadcrumbLinks = [
+		{ title: 'Developer', url: '/' },
+		{ title: product.name, url: `/${productSlug}` },
+		{ title: 'Playground', url: `/${productSlug}/playground` },
+		{
+			title: playground.name,
+			url: `/${productSlug}/playground/${playgroundId}`,
+		},
+	]
+
+	const sidebarNavDataLevels = [
+		generateTopLevelSidebarNavData(product.name),
+		generateProductLandingSidebarNavData(product),
+	]
+
+	// Add playground links
+	const playgroundMenuItems = [
+		{
+			title: `${product.name} Playground`,
+			fullPath: `/${productSlug}/playground`,
+			theme: product.slug,
+			isActive: false,
+		},
+		{
+			divider: true,
+		},
+		{
+			heading: 'Playgrounds',
+		},
+		...product.playgroundConfig.labs.map((p) => ({
+			title: p.name,
+			path: `/${productSlug}/playground/${p.id}`,
+			href: `/${productSlug}/playground/${p.id}`,
+			isActive: p.id === playgroundId,
+		})),
+	]
+
+	if (product.playgroundConfig.sidebarLinks) {
+		playgroundMenuItems.push(
+			{
+				divider: true,
+			},
+			{
+				heading: 'Resources',
+			},
+			...product.playgroundConfig.sidebarLinks.map((link) => ({
+				title: link.title,
+				path: link.href,
+				href: link.href,
+				isActive: false,
+			}))
+		)
+	}
+
+	sidebarNavDataLevels.push({
+		backToLinkProps: {
+			text: `${product.name} Home`,
+			href: `/${product.slug}`,
+		},
+		title: 'Playground',
+		menuItems: playgroundMenuItems,
+		showFilterInput: false,
+		visuallyHideTitle: true,
+		levelButtonProps: {
+			levelUpButtonText: `${product.name} Home`,
+			levelDownButtonText: 'Previous',
+		},
+	})
+
+	return {
+		props: {
+			product,
+			playgroundId: playground.instruqtId,
+			playgroundName: playground.name,
+			playgroundDescription: playground.description,
+			layoutProps: {
+				breadcrumbLinks,
+				navLevels: sidebarNavDataLevels,
+			},
+		},
+	}
+}
diff --git a/src/pages/[productSlug]/playground/index.tsx b/src/pages/[productSlug]/playground/index.tsx
new file mode 100644
index 0000000000..e32edd1d94
--- /dev/null
+++ b/src/pages/[productSlug]/playground/index.tsx
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import { GetStaticPaths, GetStaticProps } from 'next'
+import { PRODUCT_DATA_MAP } from 'data/product-data-map'
+import SidebarSidecarLayout from 'layouts/sidebar-sidecar'
+import {
+	generateTopLevelSidebarNavData,
+	generateProductLandingSidebarNavData,
+} from 'components/sidebar/helpers'
+import CardLink from 'components/card-link'
+import {
+	CardTitle,
+	CardDescription,
+	CardFooter,
+} from 'components/card/components'
+import CardsGridList from 'components/cards-grid-list'
+import { BrandedHeaderCard } from 'views/product-integrations-landing/components/branded-header-card'
+import { CardBadges } from 'components/tutorial-collection-cards'
+import { ProductOption } from 'lib/learn-client/types'
+
+interface PlaygroundPageProps {
+	product: (typeof PRODUCT_DATA_MAP)[keyof typeof PRODUCT_DATA_MAP]
+	layoutProps: {
+		breadcrumbLinks: { title: string; url: string }[]
+		navLevels: any[]
+	}
+}
+
+export default function PlaygroundView({
+	product,
+	layoutProps,
+}: PlaygroundPageProps) {
+	return (
+		<SidebarSidecarLayout
+			breadcrumbLinks={layoutProps.breadcrumbLinks}
+			sidebarNavDataLevels={layoutProps.navLevels}
+		>
+			<BrandedHeaderCard
+				productSlug={product.slug}
+				heading={`${product.name} Interactive Playgrounds`}
+				description="Choose a playground to get started with hands-on learning."
+			/>
+
+			{product.playgroundConfig.description && (
+				<p className="g-type-body" style={{ marginTop: '32px' }}>
+					{product.playgroundConfig.description}
+				</p>
+			)}
+
+			<div style={{ marginTop: '32px' }}>
+				<CardsGridList fixedColumns={2}>
+					{product.playgroundConfig.labs.map((playground) => (
+						<CardLink
+							key={playground.id}
+							ariaLabel={playground.name}
+							href={`/${product.slug}/playground/${playground.id}`}
+						>
+							<CardTitle text={playground.name} />
+							{playground.description && (
+								<CardDescription text={playground.description} />
+							)}
+							<CardFooter>
+								<CardBadges
+									badges={playground.products.map(
+										(slug) => ProductOption[slug]
+									)}
+								/>
+							</CardFooter>
+						</CardLink>
+					))}
+				</CardsGridList>
+			</div>
+		</SidebarSidecarLayout>
+	)
+}
+
+export const getStaticPaths: GetStaticPaths = async () => {
+	// Only generate paths for products that have labs configured
+	const paths = Object.values(PRODUCT_DATA_MAP)
+		.filter((product) => product.playgroundConfig?.labs)
+		.map((product) => ({
+			params: { productSlug: product.slug },
+		}))
+
+	return {
+		paths,
+		fallback: false,
+	}
+}
+
+export const getStaticProps: GetStaticProps<PlaygroundPageProps> = async ({
+	params,
+}) => {
+	const productSlug = params?.productSlug as string
+	const product = PRODUCT_DATA_MAP[productSlug]
+
+	// Only show playground page if product has labs configured
+	if (!product || !product.playgroundConfig?.labs) {
+		return {
+			notFound: true,
+		}
+	}
+
+	const breadcrumbLinks = [
+		{ title: 'Developer', url: '/' },
+		{ title: product.name, url: `/${productSlug}` },
+		{ title: 'Playground', url: `/${productSlug}/playground` },
+	]
+
+	const sidebarNavDataLevels = [
+		generateTopLevelSidebarNavData(product.name),
+		generateProductLandingSidebarNavData(product),
+	]
+
+	// Add playground links
+	const playgroundMenuItems = [
+		{
+			title: `${product.name} Playground`,
+			fullPath: `/${productSlug}/playground`,
+			theme: product.slug,
+			isActive: true,
+		},
+		{
+			divider: true,
+		},
+		{
+			heading: 'Playgrounds',
+		},
+		...product.playgroundConfig.labs.map((playground) => ({
+			title: playground.name,
+			path: `/${productSlug}/playground/${playground.id}`,
+			href: `/${productSlug}/playground/${playground.id}`,
+			isActive: false,
+		})),
+	]
+
+	if (product.playgroundConfig.sidebarLinks) {
+		playgroundMenuItems.push(
+			{
+				divider: true,
+			},
+			{
+				heading: 'Resources',
+			},
+			...product.playgroundConfig.sidebarLinks.map((link) => ({
+				title: link.title,
+				path: link.href,
+				href: link.href,
+				isActive: false,
+			}))
+		)
+	}
+
+	sidebarNavDataLevels.push({
+		backToLinkProps: {
+			text: `${product.name} Home`,
+			href: `/${product.slug}`,
+		},
+		title: 'Playground',
+		menuItems: playgroundMenuItems,
+		showFilterInput: false,
+		visuallyHideTitle: true,
+		levelButtonProps: {
+			levelUpButtonText: `${product.name} Home`,
+			levelDownButtonText: 'Previous',
+		},
+	})
+
+	return {
+		props: {
+			product,
+			layoutProps: {
+				breadcrumbLinks,
+				navLevels: sidebarNavDataLevels,
+			},
+		},
+	}
+}
diff --git a/src/types/products.ts b/src/types/products.ts
index b3259e0939..55bd2ce04e 100644
--- a/src/types/products.ts
+++ b/src/types/products.ts
@@ -148,6 +148,20 @@ interface ProductData extends Product {
 	}
 	basePaths: string[]
 	rootDocsPaths: RootDocsPath[]
+	playgroundConfig?: {
+		sidebarLinks: {
+			title: string
+			href: string
+		}[]
+		description?: string
+		labs?: {
+			id: string
+			name: string
+			instruqtId: string
+			description: string
+			products: ProductSlug[]
+		}[]
+	}
 	/**
 	 * When configuring docsNavItems, authors have the option to specify
 	 * the full data structure, or use a string that matches a rootDocsPath.path
diff --git a/src/views/playground/index.tsx b/src/views/playground/index.tsx
new file mode 100644
index 0000000000..3bd00f1228
--- /dev/null
+++ b/src/views/playground/index.tsx
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import { ProductData } from 'types/products'
+import { BreadcrumbLink } from 'components/breadcrumb-bar'
+import { SidebarProps } from 'components/sidebar/types'
+import SidebarSidecarLayout from 'layouts/sidebar-sidecar'
+import InstruqtProvider from 'contexts/instruqt-lab'
+import EmbedElement from 'components/lab-embed/embed-element'
+
+interface PlaygroundViewProps {
+	product: ProductData
+	labId: string
+	layoutProps: {
+		breadcrumbLinks: BreadcrumbLink[]
+		navLevels: SidebarProps[]
+	}
+}
+
+export default function PlaygroundView({
+	product,
+	labId,
+	layoutProps,
+}: PlaygroundViewProps) {
+	return (
+		<SidebarSidecarLayout
+			breadcrumbLinks={layoutProps.breadcrumbLinks}
+			sidebarNavDataLevels={layoutProps.navLevels}
+		>
+			<div style={{ height: '80vh' }}>
+				<InstruqtProvider labId={labId} defaultActive isPlayground>
+					<EmbedElement />
+				</InstruqtProvider>
+			</div>
+		</SidebarSidecarLayout>
+	)
+}
diff --git a/src/views/playground/server.ts b/src/views/playground/server.ts
new file mode 100644
index 0000000000..7946817d24
--- /dev/null
+++ b/src/views/playground/server.ts
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import { GetStaticProps } from 'next'
+import { PRODUCT_DATA_MAP } from 'data/product-data-map'
+import { ProductData } from 'types/products'
+import { BreadcrumbLink } from 'components/breadcrumb-bar'
+import { SidebarProps } from 'components/sidebar/types'
+import {
+	generateTopLevelSidebarNavData,
+	generateProductLandingSidebarNavData,
+} from 'components/sidebar/helpers'
+
+interface PlaygroundPageProps {
+	product: ProductData
+	labId: string
+	layoutProps: {
+		breadcrumbLinks: BreadcrumbLink[]
+		navLevels: SidebarProps[]
+	}
+}
+
+export const getStaticProps: GetStaticProps<PlaygroundPageProps> = async ({
+	params,
+}) => {
+	const productSlug = params?.productSlug as string
+	const product = PRODUCT_DATA_MAP[productSlug]
+
+	// Only show playground page if product has labs configured
+	if (!product || !product.playgroundConfig?.labs?.length) {
+		return {
+			notFound: true,
+		}
+	}
+
+	const defaultLab = product.playgroundConfig.labs[0]
+
+	const breadcrumbLinks = [
+		{ title: 'Developer', url: '/' },
+		{ title: product.name, url: `/${productSlug}` },
+		{ title: 'Playground', url: `/${productSlug}/playground` },
+	]
+
+	const sidebarNavDataLevels = [
+		generateTopLevelSidebarNavData(product.name),
+		generateProductLandingSidebarNavData(product),
+	]
+
+	// Add playground links if configured
+	if (product.playgroundConfig?.sidebarLinks) {
+		const playgroundMenuItems = [
+			{
+				title: `${product.name} Playground`,
+				fullPath: `/${productSlug}/playground`,
+				theme: product.slug,
+				isActive: true,
+			},
+			{
+				divider: true,
+			},
+			{
+				heading: 'Resources',
+			},
+			...product.playgroundConfig.sidebarLinks.map((link) => ({
+				title: link.title,
+				path: link.href,
+				href: link.href,
+				isActive: false,
+			})),
+		]
+		sidebarNavDataLevels.push({
+			backToLinkProps: {
+				text: `${product.name} Home`,
+				href: `/${product.slug}`,
+			},
+			title: 'Playground',
+			menuItems: playgroundMenuItems,
+			showFilterInput: false,
+			visuallyHideTitle: true,
+			levelButtonProps: {
+				levelUpButtonText: `${product.name} Home`,
+				levelDownButtonText: 'Previous',
+			},
+		})
+	}
+
+	return {
+		props: {
+			product,
+			labId: defaultLab.instruqtId,
+			layoutProps: {
+				breadcrumbLinks,
+				navLevels: sidebarNavDataLevels,
+			},
+		},
+	}
+}