This homemade hot chocolate recipe is rich, creamy, and full of cozy chocolate flavor. It’s simple to make and customizable for any occasion!
Sure, you can buy the premade packets with pictures of snow covered ski chalets. But did you know the very best hot chocolate is made at home in just 5 minutes? After years of testing, I’ve perfected this homemade hot chocolate recipe for you! It’s creamy, rich, and luxuriously chocolaty, using cocoa powder for deep flavor and real chocolate for that silky texture.
Unlike those instant cocoa mix packets, you can control exactly how sweet and chocolatey you want it. Trust me, once you make hot chocolate from scratch, you’ll never go back to the premade stuff!
Why You’ll Love This Hot Chocolate
I’m pretty confident you’ll love this recipe, and here’s why:
- It has a rich chocolate flavor from both cocoa powder and real chocolate chips: it’s so much better than store-bought hot cocoa mix!
- There’s balanced sweetness with just enough sugar to complement the chocolate
- It’s ready in 5 minutes from start to finish: faster than running to a coffee shop
- It’s customizable with fun topping and flavor variations, and also diet swaps
- It’s great for crowds and easily scales up for holiday gatherings or winter parties
5-Star Reader Reviews




“WOW. This is over the top fabulous. So much better than recipes on the back of the cocoa containers. Wonderful depth of flavor. My husband loved it and commented on how there was a flavor that really made it stand out. This is a winner I will share as well as make. Thank you!” – Barbara




“Made a big batch – the kids loved the regular version and grown-ups loved the Bailey’s and Peppermint versions. With the chocolate chips, it was more than sweet enough. Very decadent. Thanks for a great recipe!” – Melissa W.

What You’ll Need
There’s a bit of a debate in the culinary community about what makes the best homemade hot chocolate recipe. After numerous tests, I found cocoa powder plus real chocolate is the real winner. Here’s what you’ll need:
- Unsweetened cocoa powder: This forms the foundation: I use regular unsweetened cocoa powder here. (You could also use Dutch process for a dark chocolate flavor.)
- Milk: I like to use 2% milk. Whole milk makes it extra creamy, and skim milk makes a lighter version (though I generally avoid skim here). For dairy-free options, oat milk is my top pick for a creamy texture.
- Granulated sugar: For sweetness: you can also use honey or maple syrup instead like in my healthy hot chocolate.
- Vanilla extract and cinnamon: These two in combination add an intriguing complexity to the flavor.
- Semisweet chips or dark chocolate: You can use semisweet chocolate chips, dark chocolate chips, or even chopped dark chocolate from a chocolate bar. Most dark chocolate is dairy-free, which works with the oat milk version.
Did you know? Technically, hot cocoa is made with cocoa powder, milk and sugar: it has a thinner consistency and is very sweet. Hot chocolate is made with real chocolate, and may be thicker and less sweet. Most people use the terms interchangeably!
How to Make This Hot Chocolate Recipe
There’s not much to a homemade recipe: it’s pretty much dump and whisk! Here is the outline of the process (or jump to the recipe below to get started):
- Whisk a little milk with the cocoa powder. This helps to make a paste and dissolve most of the powder. This step is essential: if you dump cocoa powder directly into hot milk, you’ll get lumps that are impossible to whisk out.
- Add the remaining ingredients. Once it’s smooth, add the rest of the ingredients.
- Heat gently without boiling. Continue heating everything over medium heat, whisking occasionally, until the chocolate is completely melted and the drink is steaming hot, about 2 minutes total. The key is to heat the milk thoroughly without letting it boil. Boiling can scorch the milk and create a skin on top.
- Taste and adjust, then serve. Adjust the sweetness level if desired, then pour into mugs and garnish with your favorite toppings. Speaking of that…

Variations & Toppings
This homemade hot chocolate recipe tastes absolutely amazing as is. Honestly, I rarely add anything else. But if you’d like, add toppings to make it next level cozy! You can also use it as part of a hot chocolate bar and let guests top their drinks as desired. Try these toppings and flavor variations:
Topping ideas
- Homemade whipped cream
- Shaved chocolate
- Cocoa powder
- Marshmallows
- Peppermint candies, crushed
- Chocolate sauce
Flavor variations
- Peppermint: Add ⅛ teaspoon peppermint extract to the 2 serving recipe below. Or go to Peppermint Hot Chocolate or Peppermint Schnapps Hot Chocolate (the adult version).
- Vegan: Use oat milk and dairy-free chocolate chips. Go to Vegan Hot Chocolate.
- Healthy: Skip the chocolate and reduce the sugar slightly. Go to Healthy Hot Chocolate.
- Spiked: Add 2 ounces aged or dark rum or bourbon to the 2 serving recipe below. Go to Spiked Hot Chocolate.
- Kahlua or Baileys: Go to Kahlua Hot Chocolate or Baileys Hot Chocolate.

Serving Ideas
This homemade hot chocolate is perfect for so many occasions. Here are a few ways I’ve served it:
- Holiday gatherings with other Christmas cocktails and drinks and hot chocolate cookies or soft gingerbread cookies
- Cozy movie nights with the family: set out bowls of mini marshmallows, whipped cream, and chocolate shavings
- Winter breakfasts or brunch, pair it with cinnamon French toast, snowman pancakes, or other Christmas breakfast ideas
- On snow days, when there’s nothing better than coming inside and wrapping your hands around a steaming mug
For a fun twist, check out my Peppermint Ice Cream and Hot Cocoa Affogato for a fun dessert!
Making a Party Size
This recipe easily doubles, triples, or scales even larger for parties. For big batches, make it on the stovetop in a large pot, then transfer it to a crockpot to keep it warm for serving (on the “Low” or “Warm” setting, whisking every 30 minutes).
Storing & Reheating
Hot chocolate is best enjoyed fresh, but cooled leftovers store up to 3 days in the refrigerator. The cocoa and chocolate may separate, which is normal.
To reheat, warm leftovers gently on the stovetop over low to medium heat, whisking frequently. You can also reheat individual servings in the microwave in 15-second bursts, stirring in between each burst.
Dietary Notes
This hot cocoa recipe is vegetarian and gluten free. For dairy free and vegan, use oat milk and dairy-free chocolate (or omit).
Frequently Asked Questions
Hot cocoa is typically made with unsweetened cocoa powder, milk, and sugar—it’s lighter, sweeter, and has a thinner consistency. Hot chocolate traditionally uses melted chocolate (from a chocolate bar or chocolate chips), which creates a thicker, richer drink that is often less sweet.
For a richer, creamier hot chocolate, use whole milk. You can also increase the chocolate chips to ½ cup for more chocolatey depth and a thicker texture. You can also stir in a tablespoon of butter at the end for French-style hot chocolate. You can also use dark chocolate or Dutch process cocoa powder for a deeper, darker chocolate flavor.
Yes! A crockpot is perfect for keeping hot chocolate warm at parties or gatherings. Make the hot chocolate on the stovetop first, then transfer it to your crockpot set on the “warm” or “low” setting. Never use the “high” setting, which can scorch the milk and overheat the chocolate.
The hot chocolate will stay warm and ready to serve for 2-3 hours. Give it a good whisk every 30 minutes to prevent a skin from forming on top.
Homemade Hot Chocolate
Here’s the very best homemade hot chocolate recipe: full of rich chocolaty flavor and easy to whip up in 5 minutes. Never buy the mix again!
- Prep Time: 3 minutes
- Cook Time: 2 minutes
- Total Time: 5 minutes
- Yield: 2 drinks
- Category: Drink
- Method: Stovetop
- Cuisine: American
- Diet: Vegetarian
Ingredients
- 3 tablespoons cocoa powder
- 2 cups 2% milk (or oat milk)
- 3 tablespoons sugar
- ¼ teaspoon vanilla extract
- 1 pinch cinnamon
- ¼ cup (1 ½ ounces) semisweet or dark chocolate chips*
Instructions
- Place a saucepan over medium heat. Add the cocoa powder and ¼ cup of the milk and whisk until the cocoa powder is mostly integrated. Whisk in the remaining milk until smooth.
- Add the remaining ingredients and heat over medium heat until the chocolate is melted, about 2 minutes. Do not boil. Serve immediately, garnished with whipped cream or marshmallows.
Notes
*You can omit the chocolate for a great cup of hot cocoa with a lighter flavor (and less calories). But the chocolate really adds richness in flavor.
Storage and leftovers notes: Hot chocolate is best enjoyed fresh, but cooled leftovers store up to 3 days in the refrigerator. The cocoa and chocolate may separate, which is normal. To reheat, warm leftovers gently on the stovetop over low to medium heat, whisking frequently. You can also reheat individual servings in the microwave in 15-second bursts, stirring in between each burst.
Crockpot / slow cooker: This recipe easily doubles, triples, or scales even larger for parties. For big batches, make it on the stovetop in a large pot, then transfer it to a crockpot to keep it warm for serving (on the “Low” or “Warm” setting, whisking every 30 minutes).
window.trCommon={“minRating”:6,”ajaxurl”:”https:\/\/www.acouplecooks.com\/wp-admin\/admin-ajax.php”,”ratingNonce”:””,”postId”:112682};
window.TastyRecipes = window.TastyRecipes || {};
window.TastyRecipes.smoothScroll = {
init() {
document.addEventListener( ‘click’, ( e ) => {
let anchor = e.target;
if ( anchor.tagName !== ‘A’ ) {
anchor = anchor.closest( ‘a.tasty-recipes-scrollto’ );
}
if ( ! anchor || ! anchor.classList.contains( ‘tasty-recipes-scrollto’ ) ) {
return;
}
const elementHref = anchor.getAttribute( ‘href’ );
if ( ! elementHref ) {
return;
}
e.preventDefault();
this.goToSelector( elementHref );
});
},
goToSelector( selector ) {
const element = document.querySelector( selector );
if ( ! element ) {
return;
}
element.scrollIntoView( { behavior: ‘smooth’ } );
}
};
document.addEventListener(
‘DOMContentLoaded’,
() => window.TastyRecipes.smoothScroll.init()
);
window.TastyRecipes = window.TastyRecipes || {};
window.TastyRecipes.cookMode = {
wakeLockApi: false,
wakeLock: false,
cookModeSelector: ‘.tasty-recipes-cook-mode’,
init() {
if (“wakeLock” in navigator && “request” in navigator.wakeLock) {
this.wakeLockApi = navigator.wakeLock;
}
const cookModes = document.querySelectorAll(this.cookModeSelector);
if (cookModes.length > 0) {
for (const cookMode of cookModes) {
if (this.wakeLockApi) {
cookMode.querySelector(‘input[type=”checkbox”]’).addEventListener(“change”, event => {
this.checkboxChange(event.target);
}, false);
} else {
cookMode.style.display = “none”;
}
}
}
},
checkboxChange(checkbox) {
if (checkbox.checked) {
this.lock();
} else {
this.unlock();
}
},
setCheckboxesState(state) {
const checkboxes = document.querySelectorAll(this.cookModeSelector + ‘ input[type=”checkbox”]’);
for (const checkbox of checkboxes) {
checkbox.checked = state;
}
},
async lock() {
try {
this.wakeLock = await this.wakeLockApi.request(“screen”);
this.wakeLock.addEventListener(“release”, () => {
this.wakeLock = false;
this.setCheckboxesState(false);
});
this.setCheckboxesState(true);
} catch (error) {
this.setCheckboxesState(false);
}
},
unlock() {
if (this.wakeLock) {
this.wakeLock.release();
this.wakeLock = false;
}
this.setCheckboxesState(false);
}
};
(function(callback) {
if (document.readyState !== “loading”) {
callback();
} else {
document.addEventListener(“DOMContentLoaded”, callback);
}
})(() => {
window.TastyRecipes.cookMode.init();
});
window.TastyRecipes = window.TastyRecipes || {};
window.TastyRecipes.staticTooltip = {
element: null,
tooltipElement: null,
deleting: false,
init( element ) {
if ( this.deleting ) {
return;
}
this.element = element;
this.buildElements();
},
destroy() {
if ( ! this.tooltipElement || this.deleting ) {
return;
}
this.deleting = true;
this.tooltipElement.classList.remove( ‘opened’ );
setTimeout( () => {
this.tooltipElement.remove();
this.deleting = false;
}, 500 );
},
buildElements() {
const tooltipElement = document.createElement( ‘div’ );
tooltipElement.classList.add( ‘tasty-recipes-static-tooltip’);
tooltipElement.setAttribute( ‘id’, ‘tasty-recipes-tooltip’ );
const currentTooltipElement = document.getElementById( ‘tasty-recipes-tooltip’ );
if ( currentTooltipElement ) {
document.body.replaceChild( tooltipElement, currentTooltipElement );
} else {
document.body.appendChild( tooltipElement );
}
this.tooltipElement = document.getElementById( ‘tasty-recipes-tooltip’ );
},
show() {
if ( ! this.tooltipElement ) {
return;
}
const tooltipTop = this.element.getBoundingClientRect().top
+ window.scrollY
– 10 // 10px offset.
– this.tooltipElement.getBoundingClientRect().height;
const tooltipLeft = this.element.getBoundingClientRect().left
– ( this.tooltipElement.getBoundingClientRect().width / 2 )
+ ( this.element.getBoundingClientRect().width / 2 ) – 1;
const posLeft = Math.max( 10, tooltipLeft );
this.maybeRemoveTail( posLeft !== tooltipLeft );
this.tooltipElement.setAttribute( ‘style’, ‘top:’ + tooltipTop + ‘px;left:’ + posLeft + ‘px;’ );
this.tooltipElement.classList.add( ‘opened’ );
},
maybeRemoveTail( removeTail ) {
if ( removeTail ) {
this.tooltipElement.classList.add( ‘tr-hide-tail’ );
} else {
this.tooltipElement.classList.remove( ‘tr-hide-tail’ );
}
},
changeMessage( message ) {
if ( ! this.tooltipElement ) {
return;
}
this.tooltipElement.innerHTML = message;
}
};
window.TastyRecipes.ajax = {
sendPostRequest( url, data, success, failure ) {
const xhr = new XMLHttpRequest();
xhr.open( ‘POST’, url, true );
xhr.send( this.preparePostData( data ) );
xhr.onreadystatechange = () => {
if ( 4 !== xhr.readyState ) {
return;
}
if ( xhr.status === 200 ) {
success( JSON.parse( xhr.responseText ) );
return;
}
failure( xhr );
};
xhr.onerror = () => {
failure( xhr );
};
},
preparePostData( data ) {
const formData = new FormData();
for ( const key in data ) {
formData.append( key, data[key] );
}
return formData;
},
};
window.TastyRecipes.ratings = {
defaultRating: 0,
currentRatingPercentage: 100,
savingRating: false,
init( minRating ) {
this.minRating = minRating;
this.formWatchRating();
this.closeTooltipWhenClickOutside();
this.addBodyClassBasedOnSelectedRating();
this.backwardCompFormRatingPosition();
},
formWatchRating() {
const ratings = document.querySelectorAll(‘.tasty-recipes-no-ratings-buttons [data-rating]’);
if ( ratings.length {
event.preventDefault();
this.defaultRating = event.target.closest( ‘.checked’ ).dataset.rating;
this.setCheckedStar( event.target );
this.maybeSendRating( this.defaultRating, event.target );
this.setRatingInForm( this.defaultRating );
} );
}
},
closeTooltipWhenClickOutside() {
window.addEventListener( ‘click’, e => {
// Bailout (don’t remove the tooltip) when the clicked element is a rating star, or it’s the tooltip itself.
if ( e.target.closest( ‘.tasty-recipes-rating’ ) || e.target.classList.contains( ‘tasty-recipes-static-tooltip’ ) ) {
return;
}
window.TastyRecipes.staticTooltip.destroy();
} );
},
setRatingInForm( rating ) {
const ratingInput = document.querySelector( ‘#respond .tasty-recipes-rating[value=”‘ + rating + ‘”]’ );
if ( ! ratingInput ) {
return;
}
ratingInput.click();
},
addBodyClassBasedOnSelectedRating() {
const ratingInputs = document.querySelectorAll( ‘input.tasty-recipes-rating’ );
if ( ! ratingInputs ) {
return;
}
for ( const ratingInput of ratingInputs ) {
ratingInput.addEventListener( ‘click’, currentEvent => {
const selectedRating = currentEvent.target.getAttribute( ‘value’ );
this.handleBodyClassByRating( selectedRating );
this.toggleCommentTextareaRequired( selectedRating );
} );
}
},
handleBodyClassByRating( rating ) {
if ( rating < this.minRating ) {
document.body.classList.remove( 'tasty-recipes-selected-minimum-rating' );
return;
}
document.body.classList.add( 'tasty-recipes-selected-minimum-rating' );
},
toggleCommentTextareaRequired( rating ) {
const commentTextarea = document.getElementById( 'comment' );
if ( ! commentTextarea ) {
return;
}
if ( rating {
window.TastyRecipes.staticTooltip.changeMessage( response.data.message );
window.TastyRecipes.staticTooltip.show();
this.updateAverageText( response.data, recipeCardElement );
this.maybeFillCommentForm( response.data );
// Hide the tooltip after 5 seconds.
setTimeout( () => {
this.maybeResetTooltip( recipeCardElement, response.data, rating );
}, 5000 );
},
() => {
this.resetTooltip( recipeCardElement );
}
);
},
updateAverageText( data, recipeCardElement ) {
if ( ! data.average ) {
return;
}
this.setRatingPercent( data );
if ( ! data.count ) {
return;
}
const quickLink = document.querySelector( ‘.tasty-recipes-rating-link’ );
if ( quickLink ) {
this.setTextInContainer( quickLink, data );
this.setPartialStar( quickLink );
}
const cardStars = recipeCardElement.querySelector( ‘.tasty-recipes-ratings-buttons’ );
cardStars.dataset.trDefaultRating = data.average;
this.setTextInContainer( recipeCardElement.querySelector( ‘.tasty-recipes-rating’ ), data );
},
setTextInContainer( container, data ) {
if ( ! container ) {
return;
}
if ( data.label ) {
const ratingLabelElement = container.querySelector( ‘.rating-label’ );
if ( ratingLabelElement ) {
ratingLabelElement.innerHTML = data.label;
}
return;
}
const averageElement = container.querySelector( ‘.average’ );
if ( averageElement ) {
averageElement.textContent = data.average;
}
const countElement = container.querySelector( ‘.count’ );
if ( countElement ) {
countElement.textContent = data.count;
}
},
setPartialStar( container ) {
const highestStar = container.querySelector( ‘[data-rating=”‘ + Math.ceil( this.defaultRating ) + ‘”]’ );
if ( highestStar ) {
highestStar.dataset.trClip = this.currentRatingPercentage;
}
},
setRatingPercent( data ) {
this.defaultRating = data.average.toFixed( 1 );
const parts = data.average.toFixed( 2 ).toString().split( ‘.’ );
this.currentRatingPercentage = parts[1] ? parts[1] : 100;
if ( this.currentRatingPercentage === ’00’ ) {
this.currentRatingPercentage = 100;
}
},
setCheckedStar( target ) {
const cardRatingContainer = target.closest( ‘.tasty-recipes-ratings-buttons’ );
const selectedRatingElement = cardRatingContainer.querySelector( ‘[data-tr-checked]’ );
if ( selectedRatingElement ) {
delete selectedRatingElement.dataset.trChecked;
}
const thisStar = target.closest( ‘.tasty-recipes-rating’ );
thisStar.dataset.trChecked = 1;
thisStar.querySelector( ‘[data-tr-clip]’ ).dataset.trClip = 100;
},
maybeFillCommentForm( data ) {
if ( ! data.comment || ! data.comment.content ) {
return;
}
const commentForm = document.querySelector( ‘#commentform’ );
if ( ! commentForm ) {
return;
}
const commentBox = commentForm.querySelector( ‘[name=comment]’ );
if ( ! commentBox || commentBox.value ) {
return;
}
// Add comment details for editing.
commentBox.innerHTML = data.comment.content;
if ( data.comment.name ) {
commentForm.querySelector( ‘[name=author]’ ).value = data.comment.name;
commentForm.querySelector( ‘[name=email]’ ).value = data.comment.email;
}
},
maybeResetTooltip( recipeCardElement, data, rating ) {
if ( this.savingRating === rating ) {
this.resetTooltip( recipeCardElement, data );
}
},
resetTooltip( recipeCardElement, data ) {
window.TastyRecipes.staticTooltip.destroy();
this.savingRating = false;
// Reset the default rating.
const cardRatingContainer = recipeCardElement.querySelector( ‘.tasty-recipes-ratings-buttons’ );
if ( cardRatingContainer ) {
this.defaultRating = ( data && data.average ) ? data.average.toFixed(1) : cardRatingContainer.dataset.trDefaultRating;
cardRatingContainer.dataset.trDefaultRating = this.defaultRating;
this.resetSelectedStar( cardRatingContainer, data );
}
},
resetSelectedStar( cardRatingContainer ) {
const selectedRatingElement = cardRatingContainer.querySelector( ‘[data-rating=”‘ + Math.ceil( this.defaultRating ) + ‘”]’ );
if ( selectedRatingElement ) {
selectedRatingElement.querySelector( ‘[data-tr-clip]’ ).dataset.trClip = this.currentRatingPercentage;
selectedRatingElement.parentNode.dataset.trChecked = 1;
}
const previousSelectedElement= cardRatingContainer.querySelector( ‘[data-tr-checked]’ );
if ( previousSelectedElement ) {
const currentSelectedRating = previousSelectedElement.querySelector(‘[data-rating]’);
if ( currentSelectedRating !== selectedRatingElement ) {
delete previousSelectedElement.dataset.trChecked;
}
}
},
backwardCompFormRatingPosition() {
const ratingsButtons = document.querySelector( ‘#respond .tasty-recipes-ratings-buttons, #tasty-recipes-comment-rating .tasty-recipes-ratings-buttons’ );
if ( ! ratingsButtons ) {
return;
}
const ratingsButtonsStyles = window.getComputedStyle(ratingsButtons);
if ( ! ratingsButtonsStyles.display.includes( ‘flex’ ) ) {
ratingsButtons.style.direction = ‘rtl’;
}
if ( typeof tastyRecipesRating !== ‘undefined’ ) {
// Select the rating that was previously selected in admin.
ratingsButtons.querySelector( ‘.tasty-recipes-rating[value=”‘ + tastyRecipesRating + ‘”]’ ).checked = true;
}
const ratingSpans = ratingsButtons.querySelectorAll( ‘.tasty-recipes-rating’ );
for (const ratingSpan of ratingSpans) {
ratingSpan.addEventListener( ‘click’, event => {
if ( ratingSpan === event.target ) {
return;
}
ratingSpan.previousElementSibling.click();
} );
}
}
};
(function(callback) {
if (document.readyState !== “loading”) {
callback();
} else {
window.addEventListener( ‘load’, callback );
}
})(() => {
window.TastyRecipes.ratings.init( window.trCommon ? window.trCommon.minRating : 4 );
});
More Cozy Drinks to Try
- 15 Hot Drinks to Take The Chill Off
- Mulled Cider
- Mulled Wine
- Hot Buttered Rum
- Irish Coffee
- London Fog
- Chai Tea Latte

Peppermint Hot Chocolate

Vegan Hot Chocolate

Spiked Hot Chocolate

Baileys Hot Chocolate
www.acouplecooks.com (Article Sourced Website)
#Homemade #Hot #Chocolate

