This delightful peach blueberry cobbler is a comforting, easy dessert that’s become a family favorite! It stars sweet summer peaches and juicy blueberries baked under a golden, buttery crust, flavored with cinnamon and vanilla. Frozen or canned fruit works, too!
Why we love this recipe
How good is an Old Fashioned peach fruit cobbler? As authors of two cookbooks and this website for almost 15 years, Alex and I have made hundreds of desserts. But one of our favorite styles has always been crisps and cobblers because they’re so simple, comforting, and delicious.
This peach blueberry cobbler was inspired by some great peaches, and it’s already a family favorite! After making peach crisp, peach oatmeal, and peach muffins, it was time for a cobbler. Sweet peaches and zingy blueberries make magic together, and the topping is a vanilla-scented mesh of a crumble and biscuit (preferable to a cake-like cobbler, in our opinion!). It works when fruit is in season or with frozen fruit, too.
Ingredient notes for peach blueberry cobbler
There’s peach cobbler and then there’s peach blueberry cobbler, which has a zingy, sweet tart flavor from the berries. It’s a great way to make a dessert when you only have a few peaches, or if you have both of these seasonal fruits on hand. Here are the ingredients you’ll need and some notes on substitutions:
- Ripe peaches: Use ripe seasonal peaches. You can also use frozen peaches or canned peaches. Frozen peaches don’t need to be defrosted; you may want to use ½ cup total sugar in the filling since they can tend to be more tart. For canned peaches, use no sugar added or use ¼ cup sugar in the filling.
- Blueberries: Use fresh blueberries, but frozen blueberries work too! They don’t need to be defrosted before using. Again, you may want to slightly increase the sugar in the filling.
- Granulated sugar: We like granulated sugar with peaches, but you can substitute brown sugar or maple syrup in the filling. We don’t recommend substituting the sugar in the topping since it’s necessary for the texture.
- Cornstarch, cinnamon, and lemon: Cornstarch adds helps the filling thicken (otherwise it’s watery). Cinnamon and lemon juice and zest add dimension to the filling. We recommend it if at all possible!
- All purpose flour, unsalted butter, and egg yolk: The egg yolk helps to make a smoother, richer texture to the cobbler topping. You can substitute salted butter if desired; just decrease the kosher salt quantity in half. Substitute gluten-free 1-to-1 flour for gluten-free.
Tips for ripening and peeling peaches
Peaches can be a tricky fruit to work with! Here are a few tips we’ve learned over the years:
- To check ripeness, give the peach a gentle squeeze. It should be slightly soft to the touch. If it feels firm, it will need a few days to ripen.
- To ripen peaches quickly, place the peaches in a paper bag. Add a banana inside the bag (it emits ethylene gas, which helps the peaches ripen quicker). Gently close the top of the bag and wait 1 to 3 days, depending on the ripeness of the peaches.
- To peel peaches quickly, pop them into boiling water for 45 seconds, then when they are cool enough to handle pull off the skin with your fingers (see How to Peel Peaches). Or if they are ripe enough, you can pull off the skin with your fingers and a paring knife when slicing them.
Variations and topping ideas
This peach blueberry cobbler is such a fun fruit dessert that you can make any time of year with frozen fruit! Here are a few ideas for stepping it up and varying the flavors:
- Orange zest: Use ¼ teaspoon orange zest in the filling for a heightened citrus vibe.
- Almond extract: Add a hint to the filling: just ⅛ to ¼ teaspoon adds depth and richness to the flavor.
- Bourbon or amaretto: Add 2 tablespoons bourbon or amaretto to the filling for a complexity in flavor.
- Blackberries, raspberries, or strawberries: All types of fresh or frozen berries work well with peaches! If using frozen berries, use ½ cup total sugar in the filling since purchased frozen berries are typically not as sweet as fresh.
- Top with vanilla ice cream, whipped cream, sweetened Greek yogurt, or creme fraiche. You can even get fancy and make infused alcoholic whipped cream like bourbon whipped cream or amaretto whipped cream, which would work well with the fruit.
Storing leftovers
This peach blueberry cobbler can be stored on the counter for up to 1 day (covered, at night). After 1 day, refrigerate any leftovers for up to 4 days. It also freezes well for several months in a sealed container; reheat it in a 350°F oven until bubbly and the topping is crisp.
Dietary notes
This peach blueberry cobbler recipe is vegetarian. For gluten-free, use 1-for-1 gluten free flour. For vegan, use vegan butter and omit the egg yolk, adding water if necessary to get the crumbles to hold together.
A few more peach recipes
Love peach desserts or other peach recipes? Some of our favorites are peach crumble, peach cobbler, a showy peach galette, or my mom’s famous fresh peach pie. We also love a great peach salad or peach burrata salad in the summer, or peach ice cream.
Peach Crumble
Peach Galette
Peach Burrata Salad
20 Fresh Peach Recipes
Frequently asked questions
Yes, you can definitely use frozen fruit: you can use them without thawing. Increase the total sugar in the filling to ½ cup.
Absolutely! This recipe is versatile and can be adapted with other fruits like raspberries, blackberries, or even apples.
Store leftover cobbler in an airtight container in the refrigerator for up to 3-4 days. You can reheat individual servings in the microwave or oven.
Yes, you can freeze the baked cobbler for up to 3 months. Wrap it tightly in plastic wrap and then again in aluminum foil before freezing. Thaw overnight in the refrigerator and reheat in the oven before serving.
Peach Blueberry Cobbler
Prep Time: 20 minutes
Cook Time: 45 minutes
Total Time: 1 hour 5 minutes
Yield: 8
Description
This delightful peach blueberry cobbler is a comforting, easy dessert that’s become a family favorite! It stars sweet summer peaches and juicy blueberries baked under a golden, buttery crust, flavored with cinnamon and vanilla. Frozen or canned fruit works, too!
Ingredients
- 4 cups peeled and sliced peaches (2 pounds; about 3 large or 4 medium; see Notes)
- 1 ½ cups blueberries; see Notes (or more cups peaches)
- ⅓ cup plus ½ cup granulated sugar, divided, plus more for sprinkling
- 1 tablespoon cornstarch (or arrowroot powder)
- 2 teaspoons cinnamon
- 2 tablespoons lemon juice, plus 1 teaspoon lemon zest
- 1 cup all-purpose flourÂ
- 1 teaspoon baking powder
- ½ teaspoon kosher salt
- 8 tablespoons unsalted butter, melted
- 1 egg yolk
- 2 teaspoons vanilla extract
Instructions
- Preheat the oven to 350°F.
- Make the filling: Peel and slice the peaches. In a medium bowl, mix them with the ⅓ cup sugar, cornstarch, cinnamon, and lemon juice. Then pour the filling into a round 9-inch pie pan, 9 x 9 inch baking dish or 7 x 11 baking dish.
- Make the topping: Meanwhile, in another large bowl, combine the flour, ½ cup sugar, baking soda, and salt. Stir in the melted butter, egg yolk, and vanilla extract and stir until it forms crumbles. Place the crumbles onto the fruit. Sprinkle with a little extra granulated sugar over the top.Â
- Bake: Bake for 45 to 50 minutes until the top is evenly golden brown and the filling is bubbly. Cool for about 30 minutes, then serve. You can leave it out on the counter for up to 1 day (covered, at night). After 1 day, refrigerate any leftovers for up to 4 days. It also freezes well for several months in a sealed container; reheat it in a 350°F oven until bubbly and the topping is crisp.
Notes
Frozen and canned fruit: You can also use frozen peaches or canned peaches. Frozen peaches don’t need to be defrosted; you may want to use ½ cup total sugar in the filling since they can tend to be more tart. For canned peaches, use no sugar added or use ¼ cup sugar in the filling. You can use frozen blueberries too; no need to defrost.
Tips for peeling: To peel peaches quickly, pop them into boiling water for 45 seconds, then when they are cool enough to handle pull off the skin with your fingers (see How to Peel Peaches). Or if they are ripe enough, you can pull off the skin with your fingers and a paring knife when slicing them.
Flavor variations: Add ¼ teaspoon orange zest, ⅛ to ¼ teaspoon almond extract, or 2 tablespoons bourbon or amaretto to the filling for complexity in flavor. Substitute fresh or frozen blackberries, strawberries, or raspberries for the berries.
Topping ideas: Top with vanilla ice cream, whipped cream, sweetened Greek yogurt, or creme fraiche. Or, make infused alcoholic whipped cream like bourbon whipped cream or amaretto whipped cream, which would work well with the fruit.
- Category: Dessert
- Method: Baked
- Cuisine: American
- Diet: Vegan
window.trCommon=”minRating”:6,”ajaxurl”:”https:\/\/www.acouplecooks.com\/wp-admin\/admin-ajax.php”,”ratingNonce”:””,”postId”:164139;
window.TastyRecipes = window.TastyRecipes || ;
window.TastyRecipes.smoothScroll = {
init()
window.addEventListener( ‘click’, e =>
let anchor = e.target;
if ( ! anchor.classList.contains( ‘tasty-recipes-scrollto’ ) ) ! 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’ );
history.pushState( , ”, selector );
};
(function( callback )
if ( document.readyState !== ‘loading’ )
callback();
else
window.addEventListener( ‘load’, callback );
)(() =>
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() ,
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 => );
,
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 ) ,
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 );
);